Problemen met query's oplossen die nooit lijken te eindigen op SQL Server
In dit artikel worden de stappen voor probleemoplossing beschreven voor het probleem waarbij u een query hebt die nooit is voltooid, of het voltooien ervan vele uren of dagen kan duren.
Wat is een nooit eindigende query?
Dit document is gericht op query's die blijven uitvoeren of compileren, dat wil gezegd, hun CPU blijft toenemen. Het is niet van toepassing op query's die worden geblokkeerd of wachten op een resource die nooit wordt vrijgegeven (de CPU blijft constant of verandert zeer weinig).
Belangrijk
Als er nog een query overblijft om de uitvoering te voltooien, wordt deze uiteindelijk voltooid. Het kan slechts een paar seconden duren of het kan enkele dagen duren.
De term die nooit eindigt, wordt gebruikt om de perceptie te beschrijven van een query die niet wordt voltooid wanneer de query uiteindelijk wordt voltooid.
Een nooit-eindigende query identificeren
Voer de volgende stappen uit om te bepalen of een query continu wordt uitgevoerd of vastgelopen op een knelpunt:
Voer de volgende query uit.
DECLARE @cntr int = 0 WHILE (@cntr < 3) BEGIN SELECT TOP 10 s.session_id, r.status, r.wait_time, r.wait_type, r.wait_resource, r.cpu_time, r.logical_reads, r.reads, r.writes, r.total_elapsed_time / (1000 * 60) 'Elaps M', SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1, ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(st.TEXT) ELSE r.statement_end_offset END - r.statement_start_offset) / 2) + 1) AS statement_text, COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + N'.' + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text, r.command, s.login_name, s.host_name, s.program_name, s.last_request_end_time, s.login_time, r.open_transaction_count, atrn.name as transaction_name, atrn.transaction_id, atrn.transaction_state FROM sys.dm_exec_sessions AS s JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st LEFT JOIN (sys.dm_tran_session_transactions AS stran JOIN sys.dm_tran_active_transactions AS atrn ON stran.transaction_id = atrn.transaction_id) ON stran.session_id =s.session_id WHERE r.session_id != @@SPID ORDER BY r.cpu_time DESC SET @cntr = @cntr + 1 WAITFOR DELAY '00:00:05' END
Controleer de voorbeelduitvoer.
De stappen voor probleemoplossing in dit artikel zijn specifiek van toepassing wanneer u een uitvoer ziet die vergelijkbaar is met de volgende, waarbij de CPU evenredig toeneemt met de verstreken tijd, zonder aanzienlijke wachttijden. Het is belangrijk te weten dat wijzigingen
logical_reads
in dit geval niet relevant zijn, omdat sommige CPU-gebonden T-SQL-aanvragen helemaal geen logische leesbewerkingen uitvoeren (bijvoorbeeld berekeningen of eenWHILE
lus uitvoeren).session_id status cpu_time logical_reads wait_time wait_type 56 actief 7038 101000 0 NULL 56 uitvoerbaar 12040 301000 0 NULL 56 actief 17020 523000 0 NULL Dit artikel is niet van toepassing als u een wachtscenario ziet dat vergelijkbaar is met het volgende scenario waarin de CPU niet erg verandert of verandert, en de sessie wacht op een resource.
session_id status cpu_time logical_reads wait_time wait_type 56 onderbroken 0 3 8312 LCK_M_U 56 onderbroken 0 3 13318 LCK_M_U 56 onderbroken 0 5 18331 LCK_M_U
Zie Wachten of knelpunten diagnosticeren voor meer informatie.
Lange compilatietijd
In zeldzame gevallen merkt u misschien dat de CPU continu toeneemt in de loop van de tijd, maar dat wordt niet aangestuurd door de uitvoering van query's. In plaats daarvan kan het worden aangestuurd door een te lange compilatie (het parseren en compileren van een query). Controleer in die gevallen de transaction_name uitvoerkolom en zoek naar een waarde van sqlsource_transform
. Deze transactienaam geeft een compilatie aan.
Diagnostische gegevens verzamelen
- SQL Server 2008 - SQL Server 2014 (vóór SP2)
- SQL Server 2014 (na SP2) en SQL Server 2016 (vóór SP1)
- SQL Server 2016 (na SP1) en SQL Server 2017
- SQL Server 2019 en latere versies
Voer de volgende stappen uit om diagnostische gegevens te verzamelen met behulp van SQL Server Management Studio (SSMS):
Leg de xml van het geschatte uitvoeringsplan voor query's vast.
Bekijk het queryplan om te zien of er duidelijke indicaties zijn van waar de traagheid vandaan kan komen. Enkele voorbeelden hiervan zijn:
- Tabel- of indexscans (bekijk geschatte rijen).
- Geneste lussen die worden aangestuurd door een enorme buitenste tabelgegevensset.
- Geneste lussen met een grote vertakking aan de binnenkant van de lus.
- Tafelspools.
- Functies in de
SELECT
lijst die lang duren om elke rij te verwerken.
Als de query op elk gewenst moment snel wordt uitgevoerd, kunt u de 'snelle' uitvoeringen vastleggen om het werkelijke XML-uitvoeringsplan te vergelijken.
Methode voor het controleren van de verzamelde plannen
In deze sectie ziet u hoe u de verzamelde gegevens kunt bekijken. Hierbij worden de meerdere XML-queryplannen (met behulp van extensie *.sqlplan) gebruikt die zijn verzameld in SQL Server 2016 SP1 en latere builds en versies.
Volg deze stappen om uitvoeringsplannen te vergelijken:
Open een eerder opgeslagen queryuitvoeringsplanbestand (.sqlplan).
Klik met de rechtermuisknop in een leeg gebied van het uitvoeringsplan en selecteer Showplan vergelijken.
Kies het tweede queryplanbestand dat u wilt vergelijken.
Zoek naar dikke pijlen die duiden op een groot aantal rijen die tussen operators stromen. Selecteer vervolgens de operator vóór of na de pijl en vergelijk het aantal werkelijke rijen tussen twee plannen.
Vergelijk de tweede en derde planning om te zien of de grootste stroom rijen in dezelfde operatoren plaatsvindt.
Hier volgt een voorbeeld:
Oplossing
Zorg ervoor dat statistieken worden bijgewerkt voor de tabellen die in de query worden gebruikt.
Zoek naar een ontbrekende indexaanveling in het queryplan en pas deze toe.
Herschrijf de query met het doel om deze te vereenvoudigen:
- Gebruik meer selectieve
WHERE
predicaten om de verwerkte gegevens vooraf te verminderen. - Breek het uit elkaar.
- Selecteer enkele onderdelen in tijdelijke tabellen en voeg ze later toe.
- Verwijder
TOP
,EXISTS
enFAST
(T-SQL) in de query's die gedurende zeer lange tijd worden uitgevoerd vanwege het doel van de optimizer-rij. U kunt ook deDISABLE_OPTIMIZER_ROWGOAL
hint gebruiken. Zie Row Goals Gone Rogue voor meer informatie. - Vermijd het gebruik van CTE's (Common Table Expressions) in gevallen waarin ze instructies combineren in één grote query.
- Gebruik meer selectieve
Probeer queryhints te gebruiken om een beter plan te maken:
HASH JOIN
ofMERGE JOIN
hintFORCE ORDER
tipFORCESEEK
tipRECOMPILE
- GEBRUIKEN
PLAN N'<xml_plan>'
als u een snel queryplan hebt dat u kunt afdwingen
Gebruik Query Store (QDS) om een goed bekend plan af te dwingen als een dergelijk plan bestaat en of uw SQL Server-versie Query Store ondersteunt.
Wachttijden of knelpunten diagnosticeren
Deze sectie is hier opgenomen als referentie voor het geval uw probleem geen langlopende CPU-rijquery is. U kunt deze gebruiken om problemen met query's op te lossen die lang zijn vanwege wachttijden.
Als u een query wilt optimaliseren die wacht op knelpunten, identificeert u hoe lang de wachttijd is en waar het knelpunt zich bevindt (het wachttype). Zodra het wachttype is bevestigd, vermindert u de wachttijd of elimineert u de wachttijd volledig.
Als u de geschatte wachttijd wilt berekenen, trekt u de CPU-tijd (werktijd) af van de verstreken tijd van een query. Normaal gesproken is de CPU-tijd de werkelijke uitvoeringstijd en het resterende deel van de levensduur van de query wacht.
Voorbeelden van het berekenen van de geschatte wachttijd:
Verstreken tijd (ms) | CPU-tijd (ms) | Wachttijd (ms) |
---|---|---|
3200 | 3000 | 200 |
7080 | 1000 | 6080 |
Het knelpunt identificeren of wachten
Voer de volgende query uit om historische langwachtquery's te identificeren (bijvoorbeeld >20% van de totale verstreken tijd is wachttijd). Deze query maakt gebruik van prestatiestatistieken voor queryplannen in de cache sinds het begin van SQL Server.
SELECT t.text, qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time, qs.total_worker_time / qs.execution_count AS avg_cpu_time, (qs.total_elapsed_time - qs.total_worker_time) / qs.execution_count AS avg_wait_time, qs.total_logical_reads / qs.execution_count AS avg_logical_reads, qs.total_logical_writes / qs.execution_count AS avg_writes, qs.total_elapsed_time AS cumulative_elapsed_time FROM sys.dm_exec_query_stats qs CROSS apply sys.Dm_exec_sql_text (sql_handle) t WHERE (qs.total_elapsed_time - qs.total_worker_time) / qs.total_elapsed_time > 0.2 ORDER BY qs.total_elapsed_time / qs.execution_count DESC
Voer de volgende query uit om query's met wachttijden langer dan 500 ms te identificeren:
SELECT r.session_id, r.wait_type, r.wait_time AS wait_time_ms FROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id WHERE wait_time > 500 AND is_user_process = 1
Als u een queryplan kunt verzamelen, controleert u de WaitStats van de eigenschappen van het uitvoeringsplan in SSMS:
- Voer de query uit met Het werkelijke uitvoeringsplan opnemen op.
- Klik met de rechtermuisknop op de meest linkse operator op het tabblad Uitvoeringsplan
- Selecteer Eigenschappen en vervolgens de eigenschap WaitStats .
- Controleer de WaitTimeMs en WaitType.
Als u bekend bent met PSSDiag-/SQLdiag - of SQL LogScout LightPerf-/GeneralPerf-scenario's, kunt u een van deze scenario's gebruiken om prestatiestatistieken te verzamelen en wachtquery's op uw SQL Server-exemplaar te identificeren. U kunt de verzamelde gegevensbestanden importeren en de prestatiegegevens analyseren met SQL Nexus.
Verwijzingen om wachttijden te elimineren of te verminderen
De oorzaken en oplossingen voor elk wachttype variëren. Er is geen algemene methode om alle wachttypen op te lossen. Hier volgen artikelen voor het oplossen van veelvoorkomende problemen met wachttypen:
- Blokkerende problemen begrijpen en oplossen (LCK_M_*)
- Problemen met blokkerende Azure SQL Database begrijpen en oplossen
- Trage SQL Server-prestaties oplossen die worden veroorzaakt door I/O-problemen (PAGEIOLATCH_*, WRITELOG, IO_COMPLETION, BACKUPIO)
- PAGELATCH_EX-conflicten met invoegen van laatste pagina oplossen in SQL Server
- Geheugen verleent uitleg en oplossingen (RESOURCE_SEMAPHORE)
- Problemen met trage query's oplossen die het gevolg zijn van ASYNC_NETWORK_IO wachttype
- Problemen met hoog HADR_SYNC_COMMIT wachttype met AlwaysOn-beschikbaarheidsgroepen oplossen
- Hoe het werkt: CMEMTHREAD en foutopsporing
- Parallelle uitvoering van wachttijden uitvoeren (CXPACKET en CXCONSUMER)
- THREADPOOL-wachttijd
Zie de tabel in Typen wachttijden voor beschrijvingen van veel wachttypen en wat ze aangeven.