Linux боюнча Powershellден MS SQL менен иштөө

Бул макала таза практикалык жана менин кайгылуу окуяма арналган

Даярданып жатат Zero Touch PROD RDS (MS SQL) үчүн, ал жөнүндө биздин кулагым чыңдалып, мен автоматташтыруунун презентациясын (POC - Proof Of Concept) жасадым: Powershell скрипттеринин жыйындысы. Презентациядан кийин бороондуу, узакка созулган кол чабуулар тынымсыз кол чабууларга айланганда, алар мага айтышты - мунун баары жакшы, бирок идеологиялык себептерден улам биздин Дженкинс кулдарыбыз Linuxда иштешет!

Бул мүмкүнбү? Windows астынан ушундай жылуу, лампа DBA алып, Linux астында Powershellдин ысыгына жабыңызбы? Бул мыкаачылык эмеспи?

Linux боюнча Powershellден MS SQL менен иштөө
Мен технологиялардын бул таң калыштуу айкалышы менен өзүмдү сүңгүүгө туура келди. Албетте, менин 30+ сценарийимдин баары иштебей калды. Таң калганым, мен баарын бир жумушчу күндүн ичинде оңдоп алдым. Мен кызуу куугунтукта жазып жатам. Ошентип, Powershell скрипттерин Windowsтан Linux'ка өткөрүп жатканда кандай тузактарга туш болушуңуз мүмкүн?

sqlcmd vs Invoke-SqlCmd

Алардын ортосундагы негизги айырманы эске сала кетейин. Жакшы эски пайдалуу sqlcmd Ал ошондой эле дээрлик бирдей иш менен Linux астында иштейт. Биз суроону -Q, киргизүү файлын -i, чыгарууну -o катары аткарабыз. Бирок файлдын аталыштары, албетте, регистрге карата жасалган. Эгер сиз -i колдонсоңуз, анда файлдын аягында жазыңыз:

GO
EXIT

Эгерде аягында EXIT жок болсо, анда sqlcmd киргизүүнү күтүүнү улантат жана эгер мурун ЧЫГУУ болбойт GO, анда акыркы буйрук иштебейт. Чыгуу файлы бардык чыгарууну, тандоону, билдирүүлөрдү, басып чыгарууну ж.б.

Invoke-SqlCmd натыйжаны DataSet, DataTables же DataRows катары чыгарат. Ошондуктан, сиз жөнөкөй тандоонун натыйжасын иштетсеңиз, колдоно аласыз sqlcmd, анын жыйынтыгын талдоо менен, татаал нерсени чыгаруу дээрлик мүмкүн эмес: бул үчүн бар Invoke-SqlCmd. Бирок бул команданын да өзүнүн тамашалары бар:

  • Эгер сиз ага файлды аркылуу өткөрүп берсеңиз -InputFileошондо ЧЫГУУ кереги жок, андан тышкары, ал синтаксистик катаны жаратат
  • -OutputFile жок, команда сизге натыйжаны объект катары кайтарат
  • Серверди көрсөтүү үчүн эки синтаксис бар: -ServerInstance -Колдонуучунун аты -Сырсөз -Маалымат базасы жана аркылуу -ConnectionString. Кызык жери, биринчи учурда 1433дөн башка портту көрсөтүү мүмкүн эмес.
  • текст чыгаруу, PRINT деп жазыңыз, ал жөн гана "кармалды" sqlcmdүчүн Invoke-SqlCmd бир көйгөй болуп саналат
  • Жана эң маанилүү: Кыязы, сиздин Linuxуңузда бул cmdlet жок!

А бул негизги көйгөй. Март айында гана бул cmdlet Windows эмес платформалар үчүн жеткиликтүү болуп калды, жана акыры биз алдыга жыла алабыз!

Өзгөрмө алмаштыруу

sqlcmd -v аркылуу өзгөрмө алмаштырууга ээ, мисалы:

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

SQL скриптинде биз алмаштырууларды колдонобуз:

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

Мына ушундай. In *nix өзгөрмө алмаштыруулар иштебейт... Параметр -v этибарга алынбады. У Invoke-SqlCmd этибарга алынбаган -Өзгөрмөлөр. Өзгөрмөлөрдүн өзүн көрсөткөн параметр этибарга алынбаганы менен, алмаштыруулардын өзү иштейт — сиз Shellден каалаган өзгөрмөлөрдү колдоно аласыз. Бирок, мен өзгөрмөлөргө таарындым жана аларга такыр көз каранды болбоону чечтим жана орой жана примитивдүү иш кылдым, анткени SQL скрипттери кыска:

# 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"

Бул, сиз түшүнгөндөй, Unix версиясынан мурунтан эле сыноо.

Файлдар жүктөлүүдө

Windows версиясында ар кандай операция аудит менен коштолгон: биз sqlcmd иштеттик, чыгуу файлында кандайдыр бир кыянаттыктарды алдык, бул файлды аудит пластинкасына тиркедик. Бактыга жараша, SQL сервери Дженкинс менен бир серверде иштеген, ал төмөнкүдөй болгон:

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

Ошентип, биз BCP файлын толугу менен жутуп, аны аудит таблицасынын nvarchar(max) талаасына киргизебиз. Албетте, бул бүт система бузулду, анткени SQL серверинин ордуна мен RDS алдым, ал эми BULK INSERT файлга эксклюзивдүү кулпуну алуу аракетинен улам UNC аркылуу такыр иштебейт, ал эми RDS менен бул жалпысынан бузулган. эң башталышы. Ошентип, мен аудитти сап боюнча сактоо менен системанын дизайнын өзгөртүүнү чечтим:

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

Жана бул таблицага мындай жаз:

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() 
  }  

Мазмунду тандоо үчүн n (иденттик) тартибин тандап, ID боюнча тандоо керек.

Кийинки макалада мен мунун баары Дженкинс менен кандай байланышта экени жөнүндө кененирээк айтып берем.

Source: www.habr.com

Комментарий кошуу