Линукс дээр Powershell-ийн MS SQL-тэй ажиллах

Энэ нийтлэл нь практик бөгөөд миний гунигтай түүхэнд зориулагдсан болно

-д бэлдэж байна Zero Touch PROD Бидний бүх чих шуугиж байсан RDS (MS SQL)-ийн хувьд би автоматжуулалтын танилцуулга (POC - Proof Of Concept) хийсэн: Powershell скриптүүдийн багц. Танилцуулгын дараа шуургатай, удаан үргэлжилсэн алга ташилт намжиж, тасралтгүй алга ташилт болон хувирахад тэд надад хэлэв - энэ бүхэн сайн, гэхдээ зөвхөн үзэл суртлын шалтгаанаар л манай Женкинсийн боолууд Линукс дээр ажилладаг!

Энэ боломжтой юу? Ийм дулаан, чийдэнгийн DBA-г Windows доороос аваад Линукс дээр powershell-ийн халуунд наачих уу? Энэ харгис биш гэж үү?

Линукс дээр Powershell-ийн MS SQL-тэй ажиллах
Би энэ хачирхалтай технологийн хослолд өөрийгөө шингээх хэрэгтэй болсон. Мэдээжийн хэрэг, миний бүх 30 гаруй скрипт ажиллахаа больсон. Гайхсан нь ажлын нэг өдрийн дотор бүгдийг засч чадсан. Би халуухан хөөцөлдөж бичиж байна. Тэгэхээр, Powershell скриптийг Windows-ээс Линукс руу шилжүүлэхэд ямар бэрхшээл тулгарч болох вэ?

sqlcmd vs Invoke-SqlCmd

Тэдний хоорондох гол ялгааг танд сануулъя. Хуучин сайн хэрэглүүр sqlcmd Энэ нь бараг ижил функцтэй Линукс дээр ажилладаг. Бид хүсэлтийг -Q, оролтын файлыг -i, гаралтыг -o гэж дамжуулдаг. Гэхдээ мэдээжийн хэрэг файлын нэрсийг том жижиг жижиг үсгээр бичсэн байдаг. Хэрэв та -i ашигладаг бол файлын төгсгөлд бичнэ үү:

GO
EXIT

Төгсгөлд нь EXIT байхгүй бол sqlcmd оролтыг хүлээнэ. ГАРАХ болохгүй GO, дараа нь сүүлчийн тушаал ажиллахгүй болно. Гаралтын файл нь бүх гаралт, сонголт, мессеж, хэвлэх гэх мэтийг агуулна.

Invoke-SqlCmd нь үр дүнг DataSet, DataTables эсвэл DataRow хэлбэрээр гаргадаг. Тиймээс, хэрэв та энгийн сонголтын үр дүнг боловсруулбал ашиглаж болно sqlcmd, түүний гаралтыг задлан шинжилсний дараа ямар нэг нарийн төвөгтэй зүйлийг гаргаж авах нь бараг боломжгүй юм: учир нь ийм байдаг Invoke-SqlCmd. Гэхдээ энэ багт бас өөрийн гэсэн хошигнол бий.

  • Хэрэв та түүн рүү файл шилжүүлбэл -InputFileДараа нь ГАРАХ шаардлагагүй, үүнээс гадна энэ нь синтаксийн алдаа гаргадаг
  • -Гаралтын файл үгүй, тушаал нь үр дүнг объект болгон буцааж өгнө
  • Серверийг тодорхойлох хоёр синтакс байдаг: -ServerInstance -Хэрэглэгчийн нэр -Нууц үг -Өгөгдлийн сан ба дамжуулан -ConnectionString. Хачирхалтай нь эхний тохиолдолд 1433-аас өөр портыг зааж өгөх боломжгүй юм.
  • Текстийн гаралт, PRINT гэж бичээд "барьсан" sqlcmdтөлөө Invoke-SqlCmd асуудал юм
  • Мөн хамгийн чухал нь: Таны Линукс энэ командлетгүй байх магадлалтай!

Мөн энэ бол гол асуудал юм. Зөвхөн XNUMX-р сард энэ команд 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)

Тэгэхээр энд байна. *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() 
  }  

Агуулгыг сонгохын тулд та ID-аар сонгох хэрэгтэй бөгөөд дарааллаар n (таних) сонгох хэрэгтэй.

Дараагийн өгүүллээр би энэ бүхэн Женкинстэй хэрхэн харьцдаг талаар илүү дэлгэрэнгүй ярих болно.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх