Darbas su MS SQL iš Powershell sistemoje Linux

Šis straipsnis yra grynai praktinis ir skirtas mano liūdnai istorijai

Ruošiamės Zero Touch PROD RDS (MS SQL), apie kurią zvimbė mūsų ausys, sukūriau automatizavimo pristatymą (POC – Proof Of Concept): Powershell scenarijų rinkinį. Po pristatymo, kai audringi, užsitęsę plojimai nutilo, peraugę į nepaliaujamus plojimus, jie man pasakė – visa tai gerai, bet tik dėl ideologinių priežasčių visi mūsų Jenkins vergai dirba Linux!

ar tai įmanoma? Paimkite tokį šiltą, lempą DBA iš „Windows“ ir priklijuokite jį „Powershell“ įkarštyje „Linux“? Argi tai ne žiauru?

Darbas su MS SQL iš Powershell sistemoje Linux
Teko pasinerti į šį keistą technologijų derinį. Žinoma, visi mano 30+ scenarijų nustojo veikti. Mano nuostabai, viską pavyko sutvarkyti per vieną darbo dieną. Rašau siekdamas karšto siekio. Taigi, su kokiais sunkumais galite susidurti perkeldami „Powershell“ scenarijus iš „Windows“ į „Linux“?

sqlcmd vs Invoke-SqlCmd

Leiskite man priminti pagrindinį skirtumą tarp jų. Senas geras įrankis sqlcmd Jis taip pat veikia su Linux, su beveik identiškomis funkcijomis. Perduodame užklausą vykdyti -Q, įvesties failą kaip -i, o išvestį - kaip -o. Tačiau failų pavadinimuose, žinoma, skiriamos didžiosios ir mažosios raidės. Jei naudojate -i, tada failo pabaigoje parašykite:

GO
EXIT

Jei pabaigoje nėra EXIT, tada sqlcmd lauks įvesties, o jei anksčiau EXIT nebus GO, tada paskutinė komanda neveiks. Išvesties faile yra visa išvestis, atrankos, pranešimai, spausdinimas ir kt.

„Invoke-SqlCmd“ pateikia rezultatą kaip „DataSet“, „DataTables“ arba „DataRows“. Todėl, jei apdorojate paprasto pasirinkimo rezultatą, galite naudoti sqlcmd, išnagrinėjus jo išvestį, beveik neįmanoma išvesti kažko sudėtingo: tam yra Invoke-SqlCmd. Tačiau ši komanda turi ir savų juokelių:

  • Jei perduosite jai failą per - Įvesties failas, Tada EXIT nereikalingas, be to, sukuriama sintaksės klaida
  • - Išvesties failas ne, komanda grąžina jums rezultatą kaip objektą
  • Serveriui nurodyti yra dvi sintaksės: -ServerInstance -Vartotojo vardas -Slaptažodis -Duomenų bazė ir per -Prisijungimo eilutė. Kaip bebūtų keista, pirmuoju atveju negalima nurodyti kito uosto nei 1433.
  • teksto išvestis, įveskite PRINT, kuri tiesiog „pagaunama“ sqlcmdInvoke-SqlCmd yra problema
  • Ir svarbiausia: Greičiausiai jūsų Linux neturi šios cmdlet!

Ir tai yra pagrindinė problema. Tik kovo mėnesį ši cmdlet tapo prieinama ne Windows platformoms, ir pagaliau galime judėti į priekį!

Kintamasis pakeitimas

sqlcmd turi kintamąjį pakeitimą naudojant -v, pavyzdžiui, taip:

# $conn содержит начало команды sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res 
  -v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd

SQL scenarijuje naudojame pakaitalus:

set @spid=$(spid)
set @age=$(age)

Taigi čia yra. In *nix kintamųjų pakaitalai neveikia. Parametras -v ignoruojamas. U Invoke-SqlCmd ignoruojamas - Kintamieji. Nors parametras, nurodantis pačius kintamuosius, yra ignoruojamas, patys keitimai veikia – galite naudoti bet kokius „Shell“ kintamuosius. Tačiau mane įžeidė kintamieji ir nusprendžiau nuo jų visiškai nepriklausyti, elgiausi grubiai ir primityviai, nes SQL scenarijai yra trumpi:

# prepend the parameters  
"declare @age int, @spid int" | Add-Content "q.sql"
"set @spid=" + $spid | Add-Content "q.sql"
"set @age=" + $age | Add-Content "q.sql"

foreach ($line in Get-Content "Sqlserver/Automation/KillSpid.sql") { 
  $line | Add-Content "q.sql" 
  }
$cmd = "/opt/mssql-tools/bin/" + $conn + " -i q.sql -o res.log"

Tai, kaip suprantate, yra testas jau iš Unix versijos.

Failų įkėlimas

Windows versijoje bet kokia operacija buvo kartu su auditu: paleidome sqlcmd, gavome kažkokį piktnaudžiavimą išvesties faile, pridėjome šį failą prie audito plokštės. Laimei, SQL serveris dirbo tame pačiame serveryje kaip ir Jenkins, tai buvo padaryta maždaug taip:

CREATE procedure AuditUpload
  @id int, @filename varchar(256)
as
  set nocount on
  declare @sql varchar(max)

  CREATE TABLE #multi (filer NVARCHAR(MAX))
  set @sql='BULK INSERT #multi FROM '''+@filename
    +''' WITH (ROWTERMINATOR = '' '',CODEPAGE = ''ACP'')'
  exec (@sql)
  select @sql=filer from #multi
  update JenkinsAudit set multiliner=@sql where ID=@id
  return

Taigi, mes visiškai praryjame BCP failą ir įdedame jį į audito lentelės lauką nvarchar(max). Žinoma, visa ši sistema subyrėjo, nes vietoj SQL serverio gavau RDS, o BULK INSERT išvis neveikia per UNC dėl bandymo paimti išskirtinį failo užraktą, o naudojant RDS tai apskritai yra pasmerkta pati pradžia. Taigi nusprendžiau pakeisti sistemos dizainą, įrašydamas auditą eilutę po eilutės:

CREATE TABLE AuditOut (
  ID int NULL,
  TextLine nvarchar(max) NULL,
  n int IDENTITY(1,1) PRIMARY KEY
  )

Ir šioje lentelėje parašykite taip:

function WriteAudit([string]$Filename, [string]$ConnStr, 
     [string]$Tabname, [string]$Jobname)
{
  # get $lastid of the last execution  -- проскипано для статьи
	
  #create grid and populate it with data from file
  $audit =  Get-Content $Filename
  $DT = new-object Data.DataTable   

  $COL1 =  new-object Data.DataColumn; 
  $COL1.ColumnName = "ID"; 
  $COL1.DataType =  [System.Type]::GetType("System.Int32") 

  $COL2 =  new-object Data.DataColumn; 
  $COL2.ColumnName = "TextLine"; 
  $COL2.DataType =  [System.Type]::GetType("System.String") 
  
  $DT.Columns.Add($COL1) 
  $DT.Columns.Add($COL2) 
  foreach ($line in $audit) 
    { 
    $DR = $dt.NewRow()   
    $DR.Item("ID") = $lastid
    $DR.Item("TextLine") = $line
    $DT.Rows.Add($DR)   
    } 

  # write it to table
  $conn=new-object System.Data.SqlClient.SQLConnection 
  $conn.ConnectionString = $ConnStr
  $conn.Open() 
  $bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $ConnStr
  $bulkCopy.DestinationTableName = $Tabname 
  $bulkCopy.BatchSize = 50000
  $bulkCopy.BulkCopyTimeout = 0
  $bulkCopy.WriteToServer($DT) 
  $conn.Close() 
  }  

Norint pasirinkti turinį, reikia pasirinkti pagal ID, pasirenkant eilės tvarka n (tapatybė).

Kitame straipsnyje aš išsamiau papasakosiu apie tai, kaip visa tai sąveikauja su Jenkinsu.

Šaltinis: www.habr.com

Добавить комментарий