ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಪವರ್‌ಶೆಲ್‌ನಿಂದ MS SQL ನೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲಾಗುತ್ತಿದೆ

ಈ ಲೇಖನವು ಸಂಪೂರ್ಣವಾಗಿ ಪ್ರಾಯೋಗಿಕವಾಗಿದೆ ಮತ್ತು ನನ್ನ ದುಃಖದ ಕಥೆಗೆ ಸಮರ್ಪಿಸಲಾಗಿದೆ

ತಯಾರಾಗುತ್ತಿದೆ ಝೀರೋ ಟಚ್ PROD RDS (MS SQL) ಗಾಗಿ, ನಮ್ಮ ಎಲ್ಲಾ ಕಿವಿಗಳು ಝೇಂಕರಿಸುತ್ತಿದ್ದವು, ನಾನು ಸ್ವಯಂಚಾಲಿತತೆಯ ಪ್ರಸ್ತುತಿಯನ್ನು (POC - ಪ್ರೂಫ್ ಆಫ್ ಕಾನ್ಸೆಪ್ಟ್) ಮಾಡಿದ್ದೇನೆ: ಪವರ್‌ಶೆಲ್ ಸ್ಕ್ರಿಪ್ಟ್‌ಗಳ ಸೆಟ್. ಪ್ರಸ್ತುತಿಯ ನಂತರ, ಬಿರುಗಾಳಿಯ, ದೀರ್ಘಕಾಲದ ಚಪ್ಪಾಳೆ ಸತ್ತುಹೋದಾಗ, ನಿಲ್ಲದ ಚಪ್ಪಾಳೆಗಳಾಗಿ ಮಾರ್ಪಟ್ಟಾಗ, ಅವರು ನನಗೆ ಹೇಳಿದರು - ಇದೆಲ್ಲವೂ ಒಳ್ಳೆಯದು, ಆದರೆ ಸೈದ್ಧಾಂತಿಕ ಕಾರಣಗಳಿಗಾಗಿ, ನಮ್ಮ ಎಲ್ಲಾ ಜೆಂಕಿನ್ಸ್ ಗುಲಾಮರು ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಕೆಲಸ ಮಾಡುತ್ತಾರೆ!

ಇದು ಸಾಧ್ಯವೇ? ಅಂತಹ ಬೆಚ್ಚಗಿನ, ಲ್ಯಾಂಪ್ ಡಿಬಿಎ ಅನ್ನು ವಿಂಡೋಸ್ ಅಡಿಯಲ್ಲಿ ತೆಗೆದುಕೊಂಡು ಅದನ್ನು ಲಿನಕ್ಸ್ ಅಡಿಯಲ್ಲಿ ಪವರ್‌ಶೆಲ್‌ನ ಶಾಖದಲ್ಲಿ ಅಂಟಿಕೊಳ್ಳುವುದೇ? ಇದು ಕ್ರೂರವಲ್ಲವೇ?

ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಪವರ್‌ಶೆಲ್‌ನಿಂದ MS SQL ನೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲಾಗುತ್ತಿದೆ
ತಂತ್ರಜ್ಞಾನಗಳ ಈ ವಿಚಿತ್ರ ಸಂಯೋಜನೆಯಲ್ಲಿ ನಾನು ಮುಳುಗಬೇಕಾಯಿತು. ಸಹಜವಾಗಿ, ನನ್ನ ಎಲ್ಲಾ 30+ ಸ್ಕ್ರಿಪ್ಟ್‌ಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿವೆ. ನನ್ನ ಆಶ್ಚರ್ಯಕ್ಕೆ, ನಾನು ಒಂದು ಕೆಲಸದ ದಿನದಲ್ಲಿ ಎಲ್ಲವನ್ನೂ ಸರಿಪಡಿಸಲು ನಿರ್ವಹಿಸುತ್ತಿದ್ದೆ. ನಾನು ಬಿಸಿ ಅನ್ವೇಷಣೆಯಲ್ಲಿ ಬರೆಯುತ್ತಿದ್ದೇನೆ. ಆದ್ದರಿಂದ, ಪವರ್‌ಶೆಲ್ ಸ್ಕ್ರಿಪ್ಟ್‌ಗಳನ್ನು ವಿಂಡೋಸ್‌ನಿಂದ ಲಿನಕ್ಸ್‌ಗೆ ವರ್ಗಾಯಿಸುವಾಗ ನೀವು ಯಾವ ಅಪಾಯಗಳನ್ನು ಎದುರಿಸಬಹುದು?

sqlcmd vs ಇನ್ವೋಕ್-SqlCmd

ಅವುಗಳ ನಡುವಿನ ಮುಖ್ಯ ವ್ಯತ್ಯಾಸವನ್ನು ನಾನು ನಿಮಗೆ ನೆನಪಿಸುತ್ತೇನೆ. ಉತ್ತಮ ಹಳೆಯ ಉಪಯುಕ್ತತೆ sqlcmd ಇದು ಲಿನಕ್ಸ್ ಅಡಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ, ಬಹುತೇಕ ಒಂದೇ ರೀತಿಯ ಕಾರ್ಯವನ್ನು ಹೊಂದಿದೆ. -Q ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ನಾವು ಪ್ರಶ್ನೆಯನ್ನು ರವಾನಿಸುತ್ತೇವೆ, ಇನ್‌ಪುಟ್ ಫೈಲ್ ಅನ್ನು -i ಎಂದು ಮತ್ತು ಔಟ್‌ಪುಟ್ ಅನ್ನು -o ಎಂದು ರವಾನಿಸುತ್ತೇವೆ. ಆದರೆ ಫೈಲ್ ಹೆಸರುಗಳು, ಸಹಜವಾಗಿ, ಕೇಸ್-ಸೆನ್ಸಿಟಿವ್ ಮಾಡಲಾಗಿದೆ. ನೀವು -i ಅನ್ನು ಬಳಸಿದರೆ, ಫೈಲ್‌ನಲ್ಲಿ ಕೊನೆಯಲ್ಲಿ ಬರೆಯಿರಿ:

GO
EXIT

ಕೊನೆಯಲ್ಲಿ ಯಾವುದೇ ನಿರ್ಗಮನವಿಲ್ಲದಿದ್ದರೆ, sqlcmd ಇನ್‌ಪುಟ್‌ಗಾಗಿ ಕಾಯಲು ಮುಂದುವರಿಯುತ್ತದೆ ಮತ್ತು ಮೊದಲು ನಿರ್ಗಮಿಸಿ ಆಗುವುದಿಲ್ಲ GO, ನಂತರ ಕೊನೆಯ ಆಜ್ಞೆಯು ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ. ಔಟ್‌ಪುಟ್ ಫೈಲ್ ಎಲ್ಲಾ ಔಟ್‌ಪುಟ್, ಸೆಲೆಕ್ಟ್ಸ್, ಸಂದೇಶಗಳು, ಪ್ರಿಂಟ್ ಇತ್ಯಾದಿಗಳನ್ನು ಒಳಗೊಂಡಿದೆ.

Invoke-SqlCmd ಫಲಿತಾಂಶವನ್ನು ಡೇಟಾಸೆಟ್, ಡೇಟಾಟೇಬಲ್‌ಗಳು ಅಥವಾ ಡೇಟಾ ರೋಸ್‌ನಂತೆ ಉತ್ಪಾದಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ, ನೀವು ಸರಳ ಆಯ್ಕೆಯ ಫಲಿತಾಂಶವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಿದರೆ, ನೀವು ಬಳಸಬಹುದು sqlcmd, ಅದರ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಪಾರ್ಸ್ ಮಾಡಿದ ನಂತರ, ಸಂಕೀರ್ಣವಾದದ್ದನ್ನು ಪಡೆಯುವುದು ಅಸಾಧ್ಯ: ಇದಕ್ಕಾಗಿ ಇದೆ ಇನ್ವೋಕ್-SqlCmd. ಆದರೆ ಈ ತಂಡವು ತನ್ನದೇ ಆದ ಹಾಸ್ಯಗಳನ್ನು ಹೊಂದಿದೆ:

  • ನೀವು ಅವಳ ಮೂಲಕ ಫೈಲ್ ಅನ್ನು ವರ್ಗಾಯಿಸಿದರೆ -ಇನ್ಪುಟ್ ಫೈಲ್, ನಂತರ ನಿರ್ಗಮಿಸಿ ಅಗತ್ಯವಿಲ್ಲ, ಮೇಲಾಗಿ, ಇದು ಸಿಂಟ್ಯಾಕ್ಸ್ ದೋಷವನ್ನು ಉಂಟುಮಾಡುತ್ತದೆ
  • -ಔಟ್ಪುಟ್ ಫೈಲ್ ಇಲ್ಲ, ಆಜ್ಞೆಯು ನಿಮಗೆ ಫಲಿತಾಂಶವನ್ನು ವಸ್ತುವಾಗಿ ಹಿಂತಿರುಗಿಸುತ್ತದೆ
  • ಸರ್ವರ್ ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಲು ಎರಡು ಸಿಂಟ್ಯಾಕ್ಸ್‌ಗಳಿವೆ: -ಸರ್ವರ್ ಇನ್‌ಸ್ಟಾನ್ಸ್ -ಬಳಕೆದಾರಹೆಸರು -ಪಾಸ್‌ವರ್ಡ್ -ಡೇಟಾಬೇಸ್ ಮತ್ತು ಮೂಲಕ -ಕನೆಕ್ಷನ್ಸ್ಟ್ರಿಂಗ್. ವಿಚಿತ್ರವೆಂದರೆ, ಮೊದಲ ಪ್ರಕರಣದಲ್ಲಿ 1433 ಹೊರತುಪಡಿಸಿ ಬೇರೆ ಪೋರ್ಟ್ ಅನ್ನು ಸೂಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.
  • ಪಠ್ಯ ಔಟ್‌ಪುಟ್, ಪ್ರಿಂಟ್ ಅನ್ನು ಟೈಪ್ ಮಾಡಿ, ಅದು ಸರಳವಾಗಿ "ಕ್ಯಾಚ್" ಆಗಿದೆ 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(ಗರಿಷ್ಠ) ಕ್ಷೇತ್ರಕ್ಕೆ ತಳ್ಳುತ್ತೇವೆ. ಸಹಜವಾಗಿ, ಈ ಸಂಪೂರ್ಣ ವ್ಯವಸ್ಥೆಯು ಕುಸಿಯಿತು, ಏಕೆಂದರೆ SQL ಸರ್ವರ್ ಬದಲಿಗೆ ನಾನು RDS ಅನ್ನು ಪಡೆದುಕೊಂಡಿದ್ದೇನೆ ಮತ್ತು ಫೈಲ್‌ನಲ್ಲಿ ವಿಶೇಷ ಲಾಕ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳುವ ಪ್ರಯತ್ನದಿಂದಾಗಿ 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

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ