Database
 sql >> डेटाबेस >  >> RDS >> Database

सक्रिय धावक कौन है

आजकल, SQL सर्वर DBA समुदाय के भीतर, इस बात की अत्यधिक संभावना है कि हम प्रसिद्ध संग्रहीत प्रक्रिया sp_WhoIsActive का उपयोग करते हैं, या कम से कम सुना है। एडम मचानिक द्वारा विकसित।

एक डीबीए के रूप में अपने समय के दौरान, मैंने एसपी का उपयोग तुरंत यह जांचने के लिए किया कि किसी विशेष SQL सर्वर इंस्टेंस के अंदर क्या हो रहा है, जब यह सभी "फिंगर-पॉइंटिंग" प्राप्त कर रहा है कि एक विशेष एप्लिकेशन धीमा चल रहा है।

हालांकि, ऐसे अवसर होते हैं जहां ऐसे मुद्दे आवर्ती हो जाते हैं और संभावित अपराधी को खोजने के लिए क्या हो रहा है इसे पकड़ने के लिए एक तरीके की आवश्यकता होती है। ऐसे परिदृश्य भी हैं जहां आपके पास 3 पक्ष अनुप्रयोगों के लिए बैकएंड के रूप में कार्य करने वाले कई उदाहरण हैं। हमारे अपराधियों को खोजने के लिए संग्रहीत प्रक्रिया संभावित रूप से अच्छी तरह से काम कर सकती है।

इस लेख में, मैं एक पावरशेल टूल प्रस्तुत करूंगा जो किसी भी SQL सर्वर DBA को sp_WhoIsActive द्वारा खोजी गई क्वेरी को एकत्रित करने में मदद कर सकता है। किसी विशेष SQL सर्वर इंस्टेंस के अंदर। वह एसपी उन्हें एक निश्चित खोज स्ट्रिंग से मिलाएगा और उन्हें पोस्ट-विश्लेषण के लिए आउटपुट फ़ाइल में संग्रहीत करेगा।

प्रारंभिक विचार

स्क्रिप्ट के विवरण में गोता लगाने से पहले यहां कुछ धारणाएं दी गई हैं:

  • स्क्रिप्ट को पैरामीटर के रूप में उदाहरण का नाम प्राप्त होता है। अगर कोई पास नहीं होता है, लोकलहोस्ट स्क्रिप्ट द्वारा ग्रहण किया जाएगा।
  • स्क्रिप्ट आपसे एक विशेष खोज स्ट्रिंग के लिए पूछेगी ताकि इसकी तुलना SQL सर्वर इंस्टेंस में निष्पादित प्रश्नों के टेक्स्ट से की जा सके। यदि उनमें से किसी के साथ मेल खाता है, तो इसे एक .txt फ़ाइल में संग्रहीत किया जाएगा जिसका आप बाद में विश्लेषण कर सकते हैं।
  • आपके इंस्टेंस से संबंधित सभी जानकारी के साथ आउटपुट फ़ाइल सटीक पथ के लिए जेनरेट की गई है जहां पावरशेल स्थित है और ट्रिगर किया गया है। सुनिश्चित करें कि आपके पास लिखना . है वहाँ अनुमतियाँ।
  • यदि आप एक ही उदाहरण के लिए कई बार पावरशेल स्क्रिप्ट निष्पादित करते हैं, तो पहले से मौजूद किसी भी आउटपुट फाइल को अधिलेखित कर दिया जाएगा। केवल सबसे हाल का ही रखा जाएगा। इसलिए, यदि आपको बहुत विशिष्ट फ़ाइल रखने की आवश्यकता है, तो इसे मैन्युअल रूप से कहीं और सहेजें।
  • बंडल में एक .sql . शामिल है WhoIsActive संग्रहीत कार्यविधि को परिनियोजित करने के लिए कोड के साथ फ़ाइल करें आपके द्वारा निर्दिष्ट उदाहरण के मास्टर डेटाबेस में। स्क्रिप्ट जाँचती है कि क्या संग्रहीत कार्यविधि पहले से इंस्टेंस में मौजूद है और यदि ऐसा नहीं है तो इसे बनाता है।
    • आप इसे दूसरे डेटाबेस में परिनियोजित करना चुन सकते हैं। बस स्क्रिप्ट में आवश्यक संशोधन सुनिश्चित करें।
    • इसे डाउनलोड करें .sql सुरक्षित होस्टिंग से फ़ाइल।
  • स्क्रिप्ट डिफ़ॉल्ट रूप से प्रत्येक 10 सेकंड में SQL सर्वर आवृत्ति से जानकारी प्राप्त करने का प्रयास करेगी। लेकिन यदि आप किसी भिन्न मान का उपयोग करना चाहते हैं, तो उसे तदनुसार समायोजित करें।
  • सुनिश्चित करें कि SQL सर्वर इंस्टेंस से कनेक्ट करने के लिए आवेदन करने वाले उपयोगकर्ता के पास संग्रहित प्रक्रियाओं को बनाने और निष्पादित करने की अनुमति है। अन्यथा, यह अपने उद्देश्य को पूरा करने में विफल हो जाएगा।

पावरशेल स्क्रिप्ट का उपयोग करना

यहाँ आप स्क्रिप्ट से क्या उम्मीद कर सकते हैं:

उस स्थान पर जाएँ जहाँ आपने PowerShell स्क्रिप्ट फ़ाइल रखी है और इसे इस तरह चलाएँ:

PS C:\temp> .\WhoIsActive-Runner.ps1 SERVER\INSTANCE

मैं उदाहरण के तौर पर C:\temp का उपयोग कर रहा हूं

केवल एक चीज जो स्क्रिप्ट आपसे पूछेगी वह है लॉगिन का प्रकार जिसे आप उदाहरण से कनेक्ट करने के लिए उपयोग करना चाहते हैं।

नोट:यदि आप पावरशेल आईएसई का उपयोग करते हैं, तो संकेत स्क्रीनशॉट की तरह दिखाई देंगे। यदि आप इसे सीधे PowerShell कंसोल से चलाते हैं, तो विकल्प उसी विंडो में टेक्स्ट के रूप में संकेत दिए जाएंगे

विश्वसनीय - SQL सर्वर इंस्टेंस से कनेक्शन उसी उपयोगकर्ता के साथ किया जाएगा जो PowerShell स्क्रिप्ट के निष्पादन के लिए है। आपको कोई क्रेडेंशियल निर्दिष्ट करने की आवश्यकता नहीं है, यह उन्हें संदर्भ के आधार पर मान लेगा।

Windows लॉगिन - सही प्रमाणीकरण के लिए आपको Windows लॉगिन प्रदान करना होगा।

एसक्यूएल लॉगिन - सही प्रमाणीकरण के लिए आपको एक SQL लॉगिन प्रदान करना होगा।

कोई फर्क नहीं पड़ता कि आप कौन सा विकल्प चुनते हैं, सुनिश्चित करें कि जांच करने के लिए उसके पास पर्याप्त विशेषाधिकार हैं

यदि आप लॉगिन प्रकार चुनते हैं जिसके लिए आपको क्रेडेंशियल दर्ज करने की आवश्यकता होती है, तो विफलता के मामले में स्क्रिप्ट आपको सूचित करेगी:

निर्दिष्ट सही जानकारी के साथ, स्क्रिप्ट जाँच करेगी कि क्या SP मास्टर डेटाबेस में मौजूद है और यदि नहीं है तो इसे बनाने के लिए आगे बढ़ता है।

सुनिश्चित करें कि SP बनाने के लिए T-SQL कोड वाली .sql फ़ाइल उसी पथ पर स्थित है जहाँ स्क्रिप्ट स्थित है। .sql फ़ाइल का नाम sp_WhoIsActive.sql होना चाहिए

यदि आप किसी भिन्न .sql फ़ाइल नाम और भिन्न लक्ष्य डेटाबेस का उपयोग करना चाहते हैं, तो PowerShell स्क्रिप्ट के अंदर आवश्यक संशोधन सुनिश्चित करें:

अगला चरण होगा सर्च स्ट्रिंग प्रॉम्प्ट . SQL सर्वर इंस्टेंस के अंदर संग्रहीत प्रक्रिया के प्रत्येक निष्पादन पुनरावृत्ति द्वारा लौटाए गए किसी भी मिलान को एकत्र करने के लिए आपको इसे दर्ज करना होगा।

उसके बाद, आपको यह चुनना होगा कि आप स्क्रिप्ट निष्पादन के लिए कितना समय देना चाहते हैं।

प्रदर्शन उद्देश्यों के लिए, मैं विकल्प # 1 (5 मिनट) चुनने जा रहा हूं। मैं अपने उदाहरण में चलने वाली एक डमी क्वेरी छोड़ दूंगा। क्वेरी है विलंब प्रतीक्षा करें '00:10′ . मैं खोज स्ट्रिंग निर्दिष्ट करने जा रहा हूँ WAITFOR ताकि आप समझ सकें कि स्क्रिप्ट आपके लिए क्या करेगी।

स्क्रिप्ट का निष्पादन पूरा होने के बाद, आपको एक .txt . दिखाई देगा फ़ाइल जिसमें आपके उदाहरण का नाम और WhoIsActive . है प्रत्यय के रूप में।

यहां एक नमूना है कि स्क्रिप्ट ने क्या कैप्चर किया और उसमें सहेजा गया .txt फ़ाइल:

पावरशेल स्क्रिप्ट का पूरा कोड

यदि आप इस स्क्रिप्ट को आजमाना चाहते हैं, तो कृपया नीचे दिए गए कोड का उपयोग करें:

param(
    $instance = "localhost"
)

if (!(Get-Module -ListAvailable -Name "SQLPS")) {
    Write-Host -BackgroundColor Red -ForegroundColor White "Module Invoke-Sqlcmd is not loaded"
    exit
}

#Function to execute queries (depending on if the user will be using specific credentials or not)
function Execute-Query([string]$query,[string]$database,[string]$instance,[int]$trusted,[string]$username,[string]$password){
    if($trusted -eq 1){
        try{ 
            Invoke-Sqlcmd -Query $query -Database $database -ServerInstance $instance -ErrorAction Stop -ConnectionTimeout 5 -QueryTimeout 0      
        }
        catch{
            Write-Host -BackgroundColor Red -ForegroundColor White $_
            exit
        }
    }
    else{
        try{
            Invoke-Sqlcmd -Query $query -Database $database -ServerInstance $instance -Username $username -Password $password -ErrorAction Stop -ConnectionTimeout 5 -QueryTimeout 0
        }
         catch{
            Write-Host -BackgroundColor Red -ForegroundColor White $_
            exit
        }
    }
}

function Get-Property([string]$property,[string]$instance){
    Write-Host -NoNewline "$($property) " 
    Write-Host @greenCheck
    Write-Host ""
    switch($loginChoice){
        0       {$output = Execute-Query "SELECT SERVERPROPERTY('$($property)')" "master" $instance 1 "" ""}
        default {$output = Execute-Query "SELECT SERVERPROPERTY('$($property)')" "master" $instance 0 $login $password}   
    }
    switch($property){ 
        "EngineEdition"{
            switch($output[0]){
                1 {"$($property): Personal or Desktop Engine" | Out-File -FilePath $filePath -Append}
                2 {"$($property): Standard" | Out-File -FilePath $filePath -Append}
                3 {"$($property): Enterprise" | Out-File -FilePath $filePath -Append}
                4 {"$($property): Express" | Out-File -FilePath $filePath -Append}
                5 {"$($property): SQL Database" | Out-File -FilePath $filePath -Append}
                6 {"$($property): Microsoft Azure Synapse Analytics" | Out-File -FilePath $filePath -Append}
                8 {"$($property): Azure SQL Managed Instance" | Out-File -FilePath $filePath -Append}
                9 {"$($property): Azure SQL Edge" | Out-File -FilePath $filePath -Append}
                11{"$($property): Azure Synapse serverless SQL pool" | Out-File -FilePath $filePath -Append}            
            }
        }
        "HadrManagerStatus"{
            switch($output[0]){
                0       {"$($property): Not started, pending communication." | Out-File -FilePath $filePath -Append}
                1       {"$($property): Started and running." | Out-File -FilePath $filePath -Append}
                2       {"$($property): Not started and failed." | Out-File -FilePath $filePath -Append}
                default {"$($property): Input is not valid, an error, or not applicable." | Out-File -FilePath $filePath -Append}            
            }
        }
        "IsIntegratedSecurityOnly"{
            switch($output[0]){
                1{"$($property): Integrated security (Windows Authentication)" | Out-File -FilePath $filePath -Append}
                0{"$($property): Not integrated security. (Both Windows Authentication and SQL Server Authentication.)" | Out-File -FilePath $filePath -Append}                
            }
        }
        default{                        
            if($output[0] -isnot [DBNull]){
                "$($property): $($output[0])" | Out-File -FilePath $filePath -Append
            }else{
                "$($property): N/A" | Out-File -FilePath $filePath -Append
            }
        }
    }
    
    return
}

$filePath = ".\$($instance.replace('\','_'))_WhoIsActive.txt"
Remove-Item $filePath -ErrorAction Ignore

$loginChoices = [System.Management.Automation.Host.ChoiceDescription[]] @("&Trusted", "&Windows Login", "&SQL Login")
$loginChoice = $host.UI.PromptForChoice('', 'Choose login type for instance', $loginChoices, 0)
switch($loginChoice)
{
    1 { 
        $login          = Read-Host -Prompt "Enter Windows Login"
        $securePassword = Read-Host -Prompt "Enter Password" -AsSecureString
        $password       = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword))
      }
    2 { 
        $login          = Read-Host -Prompt "Enter SQL Login"
        $securePassword = Read-Host -Prompt "Enter Password" -AsSecureString
        $password       = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword))
      }
}

#Attempt to connect to the SQL Server instance using the information provided by the user
try{
    switch($loginChoice){
        0{
            $spExists = Execute-Query "SELECT COUNT(*) FROM sys.objects WHERE type = 'P' AND name = 'sp_WhoIsActive'" "master" $instance 1 "" ""
            if($spExists[0] -eq 0){
                Write-Host "The Stored Procedure doesn't exist in the master database."
                Write-Host "Attempting its creation..."
                try{
                    Invoke-Sqlcmd -ServerInstance $instance -Database "master" -InputFile .\sp_WhoIsActive.sql
                    Write-Host -BackgroundColor Green -ForegroundColor White "Success!"
                }
                catch{
                    Write-Host -BackgroundColor Red -ForegroundColor White $_
                    exit
                }
            }
        }
        default{
            $spExists = Execute-Query "SELECT COUNT(*) FROM sys.objects WHERE type = 'P' AND name = 'sp_WhoIsActive'" "master" $instance 0 $login $password
            if($spExists[0] -eq 0){
                Write-Host "The Stored Procedure doesn't exist in the master database."
                Write-Host "Attempting its creation..."
                try{
                    Invoke-Sqlcmd -ServerInstance $instance -Database "master" -Username $login -Password $password -InputFile .\sp_WhoIsActive.sql
                    Write-Host -BackgroundColor Green -ForegroundColor White "Success!"
                }
                catch{
                    Write-Host -BackgroundColor Red -ForegroundColor White $_
                    exit
                }
            }
        }   
    }     
}
catch{
    Write-Host -BackgroundColor Red -ForegroundColor White $_
    exit
}

#If the connection succeeds, then proceed with the retrieval of the configuration for the instance
Write-Host " _______  _______                           _______ _________ _______  _______  _______ __________________          _______ "
Write-Host "(  ____ \(  ____ )       |\     /||\     /|(  ___  )\__   __/(  ____ \(  ___  )(  ____ \\__   __/\__   __/|\     /|(  ____ \"
Write-Host "| (    \/| (    )|       | )   ( || )   ( || (   ) |   ) (   | (    \/| (   ) || (    \/   ) (      ) (   | )   ( || (    \/"
Write-Host "| (_____ | (____)| _____ | | _ | || (___) || |   | |   | |   | (_____ | (___) || |         | |      | |   | |   | || (__    "
Write-Host "(_____  )|  _____)(_____)| |( )| ||  ___  || |   | |   | |   (_____  )|  ___  || |         | |      | |   ( (   ) )|  __)   "
Write-Host "      ) || (             | || || || (   ) || |   | |   | |         ) || (   ) || |         | |      | |    \ \_/ / | (      "
Write-Host "/\____) || )             | () () || )   ( || (___) |___) (___/\____) || )   ( || (____/\   | |   ___) (___  \   /  | (____/\"
Write-Host "\_______)|/              (_______)|/     \|(_______)\_______/\_______)|/     \|(_______/   )_(   \_______/   \_/   (_______/"                                                                                                                            
Write-Host ""
$searchString = Read-Host "Enter string to lookup"  
$timerChoices = [System.Management.Automation.Host.ChoiceDescription[]] @("&1)5m", "&2)10m", "&3)15m","&4)30m","&5)Indefinitely")
$timerChoice  = $host.UI.PromptForChoice('', 'How long should the script run?', $timerChoices, 0)

Write-Host -NoNewline "Script will run "
switch($timerChoice){
    0{
        Write-Host "for 5 minutes."
        $limit = 5
    }
    1{
        Write-Host "for 10 minutes."
        $limit = 10
    }
    2{
        Write-Host "for 15 minutes."
        $limit = 15
    }
    3{
        Write-Host "for 30 minutes."
        $limit = 30
    }
    4{
        Write-Host "indefinitely (press ctrl-c to exit)."
        $limit = 2000000
    }
}
Write-Host "Start TimeStamp: $(Get-Date)"

$StopWatch = [system.diagnostics.stopwatch]::StartNew()

while($StopWatch.Elapsed.TotalMinutes -lt $limit){
    $results = Execute-Query "EXEC sp_WhoIsActive" "master" $instance 1 "" ""
    Get-Date | Out-File -FilePath $filePath -Append
    "####################################################################" | Out-File -FilePath $filePath -Append
    foreach($result in $results){
        if($result.sql_text -match $searchString){
            $result | Out-File -FilePath $filePath -Append
        }
        "####################################################################" | Out-File -FilePath $filePath -Append
    }
    Start-Sleep -s 10
}
Get-Date | Out-File -FilePath $filePath -Append
"####################################################################" | Out-File -FilePath $filePath -Append
Write-Host "End TimeStamp  : $(Get-Date)"

निष्कर्ष

आइए ध्यान रखें कि WhoIsActive उन प्रश्नों को कैप्चर नहीं करेगा जो DB इंजन द्वारा बहुत तेजी से निष्पादित किए जाते हैं। हालांकि, इस टूल का उद्देश्य उन समस्याग्रस्त प्रश्नों का पता लगाना है जो धीमे हैं और अनुकूलन दौर (या राउंड) से लाभान्वित हो सकते हैं।

आप तर्क दे सकते हैं कि एक प्रोफाइलर ट्रेस या एक विस्तारित ईवेंट सत्र एक ही चीज़ को पूरा कर सकता है। हालांकि, मुझे यह बहुत सुविधाजनक लगता है कि आप बस कई पावरशेल विंडो को आग लगा सकते हैं और एक ही समय में विभिन्न उदाहरणों के खिलाफ प्रत्येक को निष्पादित कर सकते हैं। यह कुछ ऐसा है जो कई उदाहरणों के लिए थोड़ा थकाऊ हो सकता है।

इसे एक कदम के रूप में उपयोग करके, आप थोड़ा और आगे बढ़ सकते हैं और स्क्रिप्ट द्वारा किसी भी घटना के बारे में सूचित करने के लिए एक चेतावनी तंत्र को कॉन्फ़िगर कर सकते हैं जो किसी भी क्वेरी के लिए X मिनट से अधिक समय से चल रही है।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. INSERT के साथ न्यूनतम लॉगिंग… हीप टेबल में चुनें

  2. SQL में कोडड के नियम

  3. क्लाउड में 10 सर्वश्रेष्ठ स्टार्टअप - 2018

  4. टाइम सीरीज डेटाबेस क्या है?

  5. बैकअप प्रबंधक के साथ डेटाबेस को कैसे पुनर्स्थापित करें