我已经使用stackoverflow多年了,但是今天是我第一次感到有必要提出问题。
我想知道以下代码是否可以提高效率,这是因为我正在编写脚本的多个副本,并输入不同的SQL表。
它能做什么:
效率观念:
在ForEach上方($ Data中的$ Line)上方,可以包含诸如“$ data中的foreach列”之类的内容,然后根据列数,列名和值动态构建“标准” SQL INSERT查询。
还是有一种更简单的方法将$ Data插入到其他地方的SQL表中,而这使我自己变得更加困难?我将SQL表的列名与Powershell Output保持相同,这应该有所帮助吗?
以下块用虚拟机列表(PowerCLI)填充$ Data:
$Data = @()
$AllVMs = Get-VM | SELECT *
$Entry = @()
Foreach ($VM in $AllVMs) {
$Entry = "" | Select Name,PowerState,Version,Notes,NumCpu,MemoryGB,VMHost,UsedspaceGB,ProvisionedSpaceGB,GuestId
$Entry.Name = $VM.Name
$Entry.PowerState = $VM.PowerState
$Entry.Version = $VM.Version
$Entry.Notes = $VM.Notes
$Entry.NumCpu = $VM.NumCpu
$Entry.MemoryGB = $VM.MemoryGB
$Entry.VMHost = $VM.VMHost
$Entry.UsedspaceGB = $VM.UsedspaceGB
$Entry.ProvisionedSpaceGB = $VM.ProvisionedSpaceGB
$Entry.GuestId = $VM.GuestId
$Data += $Entry
}
然后,这会用许多SQL命令(可能是数百行或数千行)填充$ SQL:
$SQL = $NULL
$SQL = $SQL + "
TRUNCATE TABLE dbo.T_VM_GUEST_DETAILS
"
ForEach ($Line in $Data) {
$Name = $NULL
$PowerState = $NULL
$Version = $NULL
$Notes = $NULL
$NumCpu = $NULL
$MemoryGB = $NULL
$VMHost = $NULL
$UsedspaceGB = $NULL
$ProvisionedSpaceGB = $NULL
$GuestId = $NULL
$Name = $Line.Name.tostring()
$PowerState = $Line.PowerState.tostring()
$Version = $Line.Version.tostring()
$Notes = $Line.Notes.tostring()
$NumCpu = $Line.NumCpu.tostring()
$MemoryGB = $Line.MemoryGB.tostring()
$VMHost = $Line.VMHost.tostring()
$UsedspaceGB = $Line.UsedspaceGB.tostring()
$ProvisionedSpaceGB = $Line.ProvisionedSpaceGB.tostring()
$GuestId = $Line.GuestId.tostring()
$SQL = $SQL + "
INSERT INTO dbo.T_VM_GUEST_DETAILS (
Name,PowerState,Version,Notes,NumCPU,MemoryGB,VMHost,UsedspaceGB,ProvisionedSpaceGB,GuestId,DATE_TIME
)
VALUES (
'$Name','$PowerState','$Version','$Notes','$NumCPU','$MemoryGB','$VMHost','$UsedspaceGB','$ProvisionedSpaceGB','$GuestId',GETDATE()
)
"
}
$SQL = $SQL + "
INSERT INTO dbo.T_VM_GUEST_DETAILS_HISTORY (
Name,PowerState,Version,Notes,NumCPU,MemoryGB,VMHost,UsedspaceGB,ProvisionedSpaceGB,GuestId,DATE_TIME
)
SELECT Name,PowerState,Version,Notes,NumCPU,MemoryGB,VMHost,UsedspaceGB,ProvisionedSpaceGB,GuestId,DATE_TIME FROM dbo.T_VM_GUEST_DETAILS
"
最佳答案
您可以在此处做一些事情来优化效率(执行时间)和简洁性。
首先,除非Get-VM完全返回您需要的属性,否则,您将不得不指定列名-但您可以限制自己只执行一次,然后重用该列表。
$ColumnNames = @(
'Name',
'PowerState',
'Version',
'Notes',
'NumCpu',
'MemoryGB',
'VMHost',
'UsedspaceGB',
'ProvisionedSpaceGB',
'GuestId'
)
从显而易见的地方开始,带有
foreach($VM in $AllVMs)
循环的第一个代码段可以完全用单个管道替换:$Data = Get-VM |Select-Object -Property $ColumnNames
不仅可以减少编写(和读取)代码的数量,而且您还会发现它比您自己的方法快。
接下来,SQL语句本身。您可以在每个INSERT语句中插入多行,而不是一次只插入一行,就像这样:
INSERT INTO dbo.T_MY_TABLE (
Id,Name,Company
) VALUES (1, "John", "MegaCorp Inc."), (2, "Joe", "SohoBiz ltd.")
根据总行数,您会发现这可以显着加快数据库侧的插入速度。
但是有一个限制,每个INSERT语句最多可以插入 1000个值行,因此首先我们需要将
$Data
数组划分为最大大小为1000的数组数组:$MaxRows = 1000
$DataMatrix = for($i = 0; $i -lt $Data.Length; $i += $MaxRows){
,($Data[$i..$($i + $MaxRows - 1)])
}
现在,我们只需要为
$DataMatrix
数组中的每个数组生成一个INSERT语句:$InsertStatements = foreach($DataSet in $DataMatrix)
{
# Let's start by generating each VALUES row
$InsertValues = foreach($Row in $DataSet)
{
@"
(
{0},GETDATE()
)
"@ -f $(@($ColumnNames|ForEach-Object{$Row."$_".ToString()}) -join ',')
# Iterate over $ColumnNames and extract the value of each "column"
}
# Now we have all the values we want to insert, now we need the insert statement itself:
@"
INSERT INTO dbo.T_VM_GUEST_DETAILS (
{0},DATE_TIME
) VALUES {1};
"@ -f $($ColumnNames -join ','),$($InsertValues -join ', ')
}
现在我们已经准备好了所有INSERT语句,我们所需要做的就是在顶部添加TRUNCATE语句,我们就可以开始了!
$SQLStatement = @"
TRUNCATE TABLE dbo.T_VM_GUEST_DETAILS
{0}
"@ -f $($InsertStatements -join "`r`n`r`n")
我将保留为HISTORY表添加INSERT语句的工作,作为OP的练习:)
(对于在这里看起来很尴尬的字符串,我深表歉意,但这会产生漂亮的SQL)
关于sql - Powershell/PowerCLI-需要更有效的将动态信息插入SQL的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34825952/