sql - Powershell/PowerCLI-需要更有效的将动态信息插入SQL的方法

标签 sql powershell powercli

我已经使用stackoverflow多年了,但是今天是我第一次感到有必要提出问题。
我想知道以下代码是否可以提高效率,这是因为我正在编写脚本的多个副本,并输入不同的SQL表。

它能做什么:

  • 查询VMware,输出到$ Data
  • 截断SQL表
  • 将$ Data插入dbo.T_VM_GUEST_DETAILS
  • 将dbo.T_VM_GUEST_DETAILS中的所有内容插入dbo.T_VM_GUEST_DETAILS_HISTORY

  • 效率观念:

    在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/

    相关文章:

    sql - 如何在另一个 SQL 语句中使用输出

    mysql - sql查询删除除主键之外的所有属性

    python - 如何使用 Pandas 截断表格?

    azure - 如何使用 Powershell 将所有 secret 从一个 Azure Keyvault 复制到另一个 Azure Keyvault

    powershell - 创建 subdir 结构,在个位数月份添加零

    powershell - ScriptText 中的 VMware PowerCLI 变量

    powershell - Powershell:无法将成员添加到集合

    vmware - 如何在PowerCLI中无提示地运行断开连接-viserver

    mysql - 结束字段中的 SQL 盲注

    powershell - INI 文件中出现奇怪的 Powershell `Set-AWSCredentials` 错误