sql - एसिंक्रोनस और थ्रेड्स में बड़ी मात्रा में एसक्यूएल प्रश्नों को कैसे निष्पादित करें




multithreading powershell (4)

  1. तालिका के आधार पर अपने प्रश्नों को समूह बनाएं और उस तालिका पर कार्रवाई करें। इसका उपयोग करके आप यह पहचान सकते हैं कि आप अपने विभिन्न तालिकाओं के खिलाफ कितने async sql क्वेरी चला सकते हैं।
  2. सुनिश्चित करें कि प्रत्येक तालिका का आकार जिसके खिलाफ आप दौड़ने जा रहे हैं। क्योंकि यदि तालिका में लाखों पंक्तियाँ होती हैं और आपका किसी अन्य तालिका के साथ जुड़ने का कार्य हो रहा है, तो समय बढ़ेगा या यदि यह CUD कार्रवाई है, तो आपकी तालिका को लॉक भी कर सकता है।
    1. और आपके सीपीयू कोर के आधार पर थ्रेड्स की संख्या भी चुनें और मान्यताओं के आधार पर नहीं। क्योंकि सीपीयू कोर एक समय में एक प्रक्रिया को चलाएगा ताकि आप कोर की संख्या बना सकें * 2 धागे कुशल हैं।

इसलिए पहले अपने डेटासेट का अध्ययन करें और फिर उपरोक्त 2 आइटम करें ताकि आप आसानी से पहचान सकें कि सभी प्रश्न क्या हैं जो समानांतर रूप से और कुशलता से चलाए जाते हैं।

आशा है कि यह कुछ विचार देगा। बेहतर है कि आप इसके लिए किसी भी पाइथन स्क्रिप्ट का उपयोग कर सकते हैं ताकि आप आसानी से एक से अधिक प्रक्रियाओं को ट्रिगर कर सकें और उनकी गतिविधियों की निगरानी भी कर सकें।

समस्या: मेरे पास भारी मात्रा में एसक्यूएल क्वेरी (लगभग 10k-20k) है और मैं उन्हें 50 (या अधिक) थ्रेड में एसिंक्रोनस चलाना चाहता हूं।

मैंने इस नौकरी के लिए एक पॉवरशेल स्क्रिप्ट लिखी है, लेकिन यह बहुत धीमी है (सभी को निष्पादित करने में लगभग 20 घंटे लगते हैं)। वांछित परिणाम 3-4 घंटे अधिकतम है।

प्रश्न: मैं इस पॉवरशेल स्क्रिप्ट को कैसे ऑप्टिमाइज़ कर सकता हूं? क्या मुझे पुनर्विचार करना चाहिए और python या c# जैसी दूसरी तकनीक का उपयोग करना चाहिए?

मुझे लगता है कि यह whoisactive का मुद्दा है, क्योंकि जब मैं जांच करता whoisactive कि whoisactive , तेजी से निष्पादित हो रहा है। नौकरियों को बनाने, बाहर निकालने और उतारने में बहुत समय लगता है, क्योंकि प्रत्येक थ्रेड के लिए अलग-अलग पीएस इंस्टेंस बनाए जाते हैं।

मेरा कोड:

$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 *

}

अद्यतन :

संसाधन: DB सर्वर एक दूरस्थ मशीन पर है:

  • 24GB RAM,
  • 8 कोर,
  • 500GB स्टोरेज,
  • SQL सर्वर 2016

हम अधिकतम सीपीयू शक्ति का उपयोग करना चाहते हैं।

फ़्रेमवर्क सीमा: क्वेरीज़ को निष्पादित करने के लिए केवल सीमा SQL सर्वर का उपयोग नहीं है। अनुरोधों को बाहर के स्रोत से आना चाहिए जैसे: पॉवर्सशेल, सी #, पायथन, आदि।


RunspacePool यहाँ जाने का तरीका है, इसे आज़माएँ:

$AllQueries = @( ... )
$MaxThreads = 5

# Each thread keeps its own connection but shares the query queue
$ScriptBlock = {
    Param($WorkQueue)

    $objConnection = New-Object System.Data.SqlClient.SqlConnection
    $objConnection.ConnectionString = 'Data Source=...'

    $objCmd = New-Object System.Data.SqlClient.SqlCommand
    $objCmd.Connection = $objConnection
    $objCmd.CommandTimeout = 0

    $query = ""

    while ($WorkQueue.TryDequeue([ref]$query)) {
        $objCmd.CommandText = $query
        $objAdapter = New-Object System.Data.SqlClient.SqlDataAdapter $objCmd
        $objDataTable = New-Object System.Data.DataTable
        $objAdapter.Fill($objDataTable) | Out-Null
    }

    $objConnection.Close()

}

# create a pool
$pool = [RunspaceFactory]::CreateRunspacePool(1, $MaxThreads)
$pool.ApartmentState  = 'STA'
$pool.Open()

# convert the query array into a concurrent queue
$workQueue = New-Object System.Collections.Concurrent.ConcurrentQueue[object]
$AllQueries | % { $workQueue.Enqueue($_) }

$threads = @()

# Create each powershell thread and add them to the pool
1..$MaxThreads | % {
    $ps = [powershell]::Create()
    $ps.RunspacePool = $pool
    $ps.AddScript($ScriptBlock) | Out-Null
    $ps.AddParameter('WorkQueue', $workQueue) | Out-Null
    $threads += [pscustomobject]@{
        Ps = $ps
        Handle = $null
    }
}

# Start all the threads
$threads | % { $_.Handle = $_.Ps.BeginInvoke() }

# Wait for all the threads to complete - errors will still set the IsCompleted flag
while ($threads | ? { !$_.Handle.IsCompleted }) {
    Start-Sleep -Seconds 1
}

# Get any results and display an errors
$threads | % {
    $_.Ps.EndInvoke($_.Handle) | Write-Output
    if ($_.Ps.HadErrors) {
        $_.Ps.Streams.Error.ReadAll() | Write-Error
    }
}

पॉवरशेल नौकरियों के विपरीत, एक RunspacePools संसाधनों को साझा कर सकता है। इसलिए सभी प्रश्नों की एक समवर्ती कतार है, और प्रत्येक थ्रेड डेटाबेस से अपना संबंध रखता है।

जैसा कि अन्य लोगों ने कहा है - जब तक आप अपने डेटाबेस का परीक्षण करने पर जोर नहीं दे रहे हैं, तब तक शायद आप प्रश्नों को थोक आवेषण में पुनर्गठित करना बेहतर समझते हैं।


आपको अपनी स्क्रिप्ट को पुनर्गठित करने की आवश्यकता है ताकि आप प्रत्येक कार्यकर्ता थ्रेड में एक डेटाबेस कनेक्शन खुला रखें, इसका उपयोग उस थ्रेड द्वारा किए गए सभी प्रश्नों के लिए करें। अभी आप प्रत्येक क्वेरी के लिए एक नया डेटाबेस कनेक्शन खोल रहे हैं, जो ओवरहेड की एक बड़ी मात्रा को जोड़ता है। उस ओवरहेड को हटाकर अपने लक्ष्य से आगे या पीछे की चीजों को गति देना चाहिए


मुझे पॉवरशेल के बारे में ज्यादा जानकारी नहीं है, लेकिन मैं काम के दौरान हर समय C # में SQL निष्पादित करता हूं।

C # के नए async / प्रतीक्षारत कीवर्ड आपके लिए वही आसान बनाते हैं जो आप बात कर रहे हैं। C # आपके मशीन के लिए धागे की इष्टतम मात्रा के साथ आपके लिए एक थ्रेड पूल भी बनाएगा।

async Task<DataTable> ExecuteQueryAsync(query)
{
    return await Task.Run(() => ExecuteQuerySync(query));
}

async Task ExecuteAllQueriesAsync()
{
    IList<Task<DataTable>> queryTasks = new List<Task<DataTable>>();

    foreach query
    {
         queryTasks.Add(ExecuteQueryAsync(query));
    }

    foreach task in queryTasks
    {
         await task;
    }
}

उपरोक्त कोड थ्रेड पूल की कार्य कतार में सभी प्रश्नों को जोड़ देगा। फिर पूरा होने से पहले उन पर प्रतीक्षा करें। परिणाम यह है कि समानांतर का अधिकतम स्तर आपके SQL के लिए पहुंच जाएगा।

उम्मीद है की यह मदद करेगा!





parallel-processing