代码之家  ›  专栏  ›  技术社区  ›  Andrea Visnenza Andy

用于调用sqlcmd的PowerShell进度条

  •  1
  • Andrea Visnenza Andy  · 技术社区  · 6 年前

    所以我尝试制作一个备份脚本,从我的MSSQL下载一个csv,然后压缩文件,然后将备份上传到AmazonS3。

    我遇到的问题是,当我每天运行脚本时,表平均有2000万行。它看起来像是永远的滞后,直到20分钟后完成。我想知道是否有一种方法可以具体地显示invoke sqlcmd的进度条。我做了一些研究,我能找到的所有例子都是在for循环上创建一个进度条,而不是单个命令的进度条。

    这是我的代码:

    ECHO "Starting Download"
        Import-Module sqlps
        #$SQLquery="SELECT * FROM dbo.$PREFIX$i"
        $SQLquery="SELECT * FROM dbo.events"
        ECHO "Executing query = $SQLquery"
    
        $hostname = "."
        $pass = "test"
        $usern = "test"
        $database = "theDB"
    
        $result=invoke-sqlcmd -ServerInstance $hostname  -query $SQLquery -HostName $hostname -Password $pass -Username $usern -Database $database -verbose
    
    
        #echo $result
        pause
        $result |export-csv -path $CSVPATH -notypeinformation
        pause
        ECHO "Starting Zip:"
        Compress-Archive -LiteralPath $CSVPATH -CompressionLevel Optimal -DestinationPath $ZIPPATH
    
        ECHO "Starting Delete: $CSVPATH "
        del "$CSVPATH" 
        echo "Removed $CSVNAME" 
    
        aws s3 cp $ZIPPATH s3://test_$ZIPNAME
    
        pause
    

    这个脚本可以工作,但是正如我所说的,我想给invoke sqlcmd添加一个进度条,这样它在下载大文件时看起来就不会冻结。

    这是到目前为止我能找到的,但这只适用于循环级数。

    $VerbosePreference = "Continue"
    Write-Verbose "Test Message"
    
    for ($a=1; $a -lt 100; $a++) {
      Write-Progress -Activity "Working..." -PercentComplete $a -CurrentOperation "$a% complete" -Status "Please wait."
      Start-Sleep -Milliseconds 100
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   kuujinbo    6 年前

    考虑到您庞大的2000万记录数据集,使用 System.Data.Common namespace . 我不知道怎么做 Export-Csv 已实现,但 System.IO.StreamWriter 对于编写大型文件非常有效。

    带有内联注释的简单测试/工作示例:

    # replace $tableName with yours
    $sqlCount = "SELECT COUNT(*) FROM dbo.$($tableName)";
    $sqlSelect = "SELECT * FROM dbo.$($tableName)";
    $provider = [System.Data.Common.DbProviderFactories]::GetFactory('System.Data.SqlClient');
    $connection = $provider.CreateConnection();
    # replace $connectionString with yours, e.g.:
    # "Data Source=$($INSTANCE-NAME);Initial Catalog=$($DATABASE-NAME);Integrated Security=True;"; 
    $connection.ConnectionString = $connectionString;
    $command = $connection.CreateCommand();
    
    # get total record count for Write-Progress
    $command.CommandText = $sqlCount;
    $connection.Open();
    $reader = $command.ExecuteReader();
    $totalRecords = 0;
    while ($reader.Read()) {
        $totalRecords = $reader[0];
    }
    $reader.Dispose();
    
    # select CSV data
    $command.CommandText = $sqlSelect;
    $reader = $command.ExecuteReader();
    
    # get CSV field names
    $columnNames = @();
    for ($i = 0; $i -lt $reader.FieldCount; $i++) {
        $columnNames += $reader.GetName($i);
    }
    
    # read and populate data one row at a time
    $values = New-Object object[] $columnNames.Length;
    $currentCount = 0;
    # replace $CSVPATH with yours
    $writer = New-Object System.IO.StreamWriter($CSVPATH);
    $writer.WriteLine(($columnNames -join ','));
    while ($reader.Read()) {
        $null = $reader.GetValues($values);
        $writer.WriteLine(($values -join ','));
        if (++$currentCount % 1000 -eq 0) {
            Write-Progress -Activity 'Reading data' `
                -Status "Finished reading $currentCount out of $totalRecords records." `
                -PercentComplete ($currentCount / $totalRecords * 100);
        }
    }
    $command.Dispose();
    $reader.Dispose();
    $connection.Dispose();
    $writer.Dispose();