首页 > 解决方案 > 如何在线程中异步执行大量 sql 查询

问题描述

问题:我有大量的 sql 查询(大约 10k-20k),我想在 50 个(或更多)线程中异步运行它们。

我为这个工作写了一个powershell脚本,但是速度很慢(全部执行大约需要20个小时)。期望的结果是最多 3-4 小时。

问题:如何优化这个 powershell 脚本?我是否应该重新考虑并使用另一种技术,例如pythonor c#

我认为这是 powershell 问题,因为当我检查whoisactive查询时执行速度很快。创建、退出和卸载作业需要花费大量时间,因为每个线程都创建了单独的 PS 实例。

我的代码:

$NumberOfParallerThreads = 50;


$Arr_AllQueries = @('Exec [mystoredproc] @param1=1, @param2=2',
                    'Exec [mystoredproc] @param1=11, @param2=22',
                    'Exec [mystoredproc] @param1=111, @param2=222')

#Creating the batches
$counter = [pscustomobject] @{ Value = 0 };
$Batches_AllQueries = $Arr_AllQueries | Group-Object -Property { 
    [math]::Floor($counter.Value++ / $NumberOfParallerThreads) 
};

forEach ($item in $Batches_AllQueries) {
    $tmpBatch = $item.Group;

    $tmpBatch | % {

        $ScriptBlock = {
            # accept the loop variable across the job-context barrier
            param($query) 
            # Execute a command

            Try 
            {
                Write-Host "[processing '$query']"
                $objConnection = New-Object System.Data.SqlClient.SqlConnection;
                $objConnection.ConnectionString = 'Data Source=...';

                $ObjCmd = New-Object System.Data.SqlClient.SqlCommand;
                $ObjCmd.CommandText = $query;
                $ObjCmd.Connection = $objConnection;
                $ObjCmd.CommandTimeout = 0;

                $objAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
                $objAdapter.SelectCommand = $ObjCmd;
                $objDataTable = New-Object System.Data.DataTable;
                $objAdapter.Fill($objDataTable)  | Out-Null;

                $objConnection.Close();
                $objConnection = $null;
            } 
            Catch 
            { 
                $ErrorMessage = $_.Exception.Message
                $FailedItem = $_.Exception.ItemName
                Write-Host "[Error processing: $($query)]" -BackgroundColor Red;
                Write-Host $ErrorMessage 
            }

        }

        # pass the loop variable across the job-context barrier
        Start-Job $ScriptBlock -ArgumentList $_ | Out-Null
    }

    # Wait for all to complete
    While (Get-Job -State "Running") { Start-Sleep 2 }

    # Display output from all jobs
    Get-Job | Receive-Job | Out-Null

    # Cleanup
    Remove-Job *

}

更新

资源:数据库服务器位于远程机器上:

我们要使用最大的 cpu 功率。

框架限制:唯一的限制是使用 SQL Server执行查询。请求应来自外部来源,例如:Powershell、C#、Python 等。

标签: sqlmultithreadingpowershellasynchronousparallel-processing

解决方案


您需要重新组织脚本,以便在每个工作线程中保持数据库连接打开,并将其用于该线程执行的所有查询。现在,您正在为每个查询打开一个新的数据库连接,这会增加大量开销。消除这种开销应该可以加快速度达到或超过您的目标。


推荐阅读