በሊኑክስ ላይ ከPowershell ከ MS SQL ጋር በመስራት ላይ

ይህ መጣጥፍ ሙሉ በሙሉ ተግባራዊ እና ለአሳዛኝ ታሪኬ የተሰጠ ነው።

ለ በመዘጋጀት ላይ ዜሮ ንክኪ PROD ለ RDS (MS SQL)፣ ስለ እሱ ጆሮአችን ሁሉ ይንጫጫል፣ እኔ አንድ አቀራረብ ሠራሁ (POC - Proof Of Concept) አውቶሜሽን፡ የኃይል ሼል ስክሪፕቶች ስብስብ። ከገለጻው በኋላ፣ አውሎ ነፋሱ፣ ረዥም ጭብጨባው ሲሞት፣ ወደ የማያባራ ጭብጨባ ሲቀየር፣ ነገሩኝ - ይህ ሁሉ ጥሩ ነው፣ ግን በርዕዮተ ዓለም ምክንያቶች ብቻ ሁሉም የጄንኪንስ ባሪያዎቻችን በሊኑክስ ላይ ይሰራሉ!

ይህ ይቻላል? እንደዚህ ያለ ሞቃታማ እና መብራት DBA ከዊንዶውስ ስር ይውሰዱ እና በሊኑክስ ስር ባለው የኃይል ሼል ሙቀት ውስጥ ይለጥፉ? ይህ ጨካኝ አይደለም?

በሊኑክስ ላይ ከPowershell ከ MS SQL ጋር በመስራት ላይ
በዚህ እንግዳ የቴክኖሎጂ ጥምረት ውስጥ ራሴን ማጥለቅ ነበረብኝ። በእርግጥ ሁሉም የእኔ 30+ ስክሪፕቶች መስራት አቁመዋል። የሚገርመኝ ግን ሁሉንም ነገር በአንድ የስራ ቀን ማስተካከል ቻልኩ። እኔ ትኩስ ማሳደድ ላይ ነው መጻፍ. ስለዚህ የኃይል ሼል ስክሪፕቶችን ከዊንዶውስ ወደ ሊኑክስ ሲያስተላልፉ ምን ችግሮች ሊያጋጥሙዎት ይችላሉ?

sqlcmd vs Invoke-SqlCmd

በመካከላቸው ያለውን ዋና ልዩነት ላስታውስህ። ጥሩ የድሮ መገልገያ sqlcmd በሊኑክስ ስር ይሰራል ከሞላ ጎደል ተመሳሳይ ተግባር ያለው። ጥያቄውን -Qን ለማስፈጸም ፣የግብዓት ፋይሉን እንደ -i እና ውጤቱን እንደ -o እናልፋለን። ነገር ግን የፋይል ስሞች, በእርግጥ, ለጉዳይ-sensitive ተደርገዋል. -i ን ከተጠቀሙ በመጨረሻ በፋይሉ ውስጥ ይፃፉ-

GO
EXIT

መጨረሻ ላይ መውጫ ከሌለ፣ sqlcmd ግቤትን ለመጠበቅ ይቀጥላል፣ እና ከዚያ በፊት ውጣ አይሆንም GO, ከዚያ የመጨረሻው ትዕዛዝ አይሰራም. የውጤት ፋይሉ ሁሉንም ውፅዓት፣ ምርጫዎች፣ መልዕክቶች፣ ህትመቶች፣ ወዘተ ይዟል።

Invoke-SqlCmd ውጤቱን እንደ DataSet፣ DataTables ወይም DataRows ያመጣል። ስለዚህ, የቀላል ምርጫን ውጤት ካስኬዱ, መጠቀም ይችላሉ sqlcmdውጤቱን ከመረመረ ፣ ውስብስብ የሆነ ነገር ማግኘት ፈጽሞ የማይቻል ነው ፣ ለዚህም አለ። ጥሪ-SqlCmd. ግን ይህ ቡድን የራሱ ቀልዶችም አሉት።

  • ፋይል ወደ እሷ ካስተላለፉ - የግቤት ፋይልእንግዲህ ውጣ አያስፈልግም, በተጨማሪም, የአገባብ ስህተትን ይፈጥራል
  • - የውጤት ፋይል አይደለም፣ ትዕዛዙ ውጤቱን እንደ ዕቃ ይመልሳል
  • አገልጋይን ለመለየት ሁለት አገባቦች አሉ። -የአገልጋይ ኢንስታንስ -የተጠቃሚ ስም -የይለፍ ቃል -ዳታቤዝ እና በኩል -ConnectionString. የሚገርመው ግን በመጀመሪያው ጉዳይ ከ1433 ውጪ ሌላ ወደብ መጥቀስ አይቻልም።
  • የጽሑፍ ውፅዓት፣ PRINT ብለው ይተይቡ፣ እሱም በቀላሉ “የተያዘ” sqlcmd፣ ለ ጥሪ-SqlCmd ችግር ነው።
  • እና ከሁሉም በላይ አስፈላጊ: ምናልባት የእርስዎ ሊኑክስ ይህ cmdlet የለውም!

እና ዋናው ችግር ይህ ነው. በዚህ cmdlet በመጋቢት ውስጥ ብቻ ዊንዶውስ ላልሆኑ መድረኮች የሚገኝ ሆነእና በመጨረሻም ወደ ፊት መሄድ እንችላለን!

ተለዋዋጭ ምትክ

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)

ስለዚህ እዚህ አለ. በ *ኒክስ ተለዋዋጭ መተካት አይሰራም. መለኪያ -v ችላ ተብሏል. ዩ ጥሪ-SqlCmd ችላ ተብሏል -ተለዋዋጮች. ምንም እንኳን ተለዋዋጮቹን የሚገልጽ ግቤት ቸል ቢባልም፣ ተተኪዎቹ እራሳቸው ይሠራሉ - ከሼል ማንኛውንም ተለዋዋጮች መጠቀም ይችላሉ። ነገር ግን፣ በተለዋዋጮቹ ተበሳጨሁ እና በእነሱ ላይ ላለመመካት ወሰንኩ፣ እና የ 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"

ይህ እርስዎ እንደተረዱት ከዩኒክስ ስሪት አስቀድሞ የተደረገ ሙከራ ነው።

ፋይሎችን በመስቀል ላይ

በዊንዶውስ ስሪት ውስጥ, ማንኛውም ክወና በኦዲት የታጀበ ነበር: እኛ 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 (ማንነት) በመምረጥ።

በሚቀጥለው ርዕስ ይህ ሁሉ ከጄንኪንስ ጋር እንዴት እንደሚገናኝ የበለጠ በዝርዝር እገልጻለሁ።

ምንጭ: hab.com

አስተያየት ያክሉ