Share via


Felsöka problem med hög CPU-användning i SQL Server

Gäller för: SQL Server

Den här artikeln innehåller procedurer för att diagnostisera och åtgärda problem som orsakas av hög CPU-användning på en dator som kör Microsoft SQL Server. Även om det finns många möjliga orsaker till hög CPU-användning i SQL Server är följande de vanligaste orsakerna:

  • Höga logiska läsningar som orsakas av tabell- eller indexgenomsökningar på grund av följande villkor:
  • Ökning av arbetsbelastning

Du kan använda följande steg för att felsöka problem med hög CPU-användning i SQL Server.

Steg 1: Kontrollera att SQL Server orsakar hög CPU-användning

Använd något av följande verktyg för att kontrollera om SQL Server faktiskt bidrar till hög CPU-användning:

  • Aktivitetshanteraren: På fliken Process kontrollerar du om värdet för CPU-kolumnen för SQL Server Windows NT-64-bitars är nära 100 procent.

  • Prestanda- och resursövervakare (perfmon)

    • Räknare: Process/%User Time, % Privileged Time
    • Instans: sqlservr
  • Du kan använda följande PowerShell-skript för att samla in räknardata under ett 60-sekundersintervall:

    $serverName = $env:COMPUTERNAME
    $Counters = @(
        ("\\$serverName" + "\Process(sqlservr*)\% User Time"), ("\\$serverName" + "\Process(sqlservr*)\% Privileged Time")
    )
    Get-Counter -Counter $Counters -MaxSamples 30 | ForEach {
        $_.CounterSamples | ForEach {
            [pscustomobject]@{
                TimeStamp = $_.TimeStamp
                Path = $_.Path
                Value = ([Math]::Round($_.CookedValue, 3))
            }
            Start-Sleep -s 2
        }
    }
    

Om % User Time är konsekvent större än 90 procent (% användartid är summan av processortiden för varje processor, är dess högsta värde 100 % * (inga processorer)), orsakar SQL Server processen hög CPU-användning. Men om % Privileged time är konsekvent större än 90 procent bidrar ditt antivirusprogram, andra drivrutiner eller en annan OS-komponent på datorn till hög CPU-användning. Du bör samarbeta med systemadministratören för att analysera rotorsaken till det här beteendet.

Steg 2: Identifiera frågor som bidrar till CPU-användning

Om processen Sqlservr.exe orsakar hög CPU-användning är den överlägset vanligaste orsaken SQL Server-frågor som utför tabell- eller indexgenomsökningar, följt av sortering, hash-åtgärder och loopar (kapslad loopoperator eller WHILE (T-SQL)). Kör följande instruktion för att få en uppfattning om hur mycket CPU som frågorna använder för närvarande, av den totala CPU-kapaciteten:

DECLARE @init_sum_cpu_time int,
        @utilizedCpuCount int 
--get CPU count used by SQL Server
SELECT @utilizedCpuCount = COUNT( * )
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE' 
--calculate the CPU usage by queries OVER a 5 sec interval 
SELECT @init_sum_cpu_time = SUM(cpu_time) FROM sys.dm_exec_requests
WAITFOR DELAY '00:00:05'
SELECT CONVERT(DECIMAL(5,2), ((SUM(cpu_time) - @init_sum_cpu_time) / (@utilizedCpuCount * 5000.00)) * 100) AS [CPU from Queries as Percent of Total CPU Capacity] 
FROM sys.dm_exec_requests

Kör följande instruktion för att identifiera de frågor som ansvarar för hög CPU-aktivitet för närvarande:

SELECT TOP 10 s.session_id,
           r.status,
           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
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
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC

Om frågor inte driver CPU:n just nu kan du köra följande instruktion för att leta efter historiska CPU-bundna frågor:

SELECT TOP 10  qs.last_execution_time, st.text AS batch_text,
    SUBSTRING(st.TEXT, (qs.statement_start_offset / 2) + 1, ((CASE qs.statement_end_offset WHEN - 1 THEN DATALENGTH(st.TEXT) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2) + 1) AS statement_text,
    (qs.total_worker_time / 1000) / qs.execution_count AS avg_cpu_time_ms,
    (qs.total_elapsed_time / 1000) / qs.execution_count AS avg_elapsed_time_ms,
    qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
    (qs.total_worker_time / 1000) AS cumulative_cpu_time_all_executions_ms,
    (qs.total_elapsed_time / 1000) AS cumulative_elapsed_time_all_executions_ms
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
ORDER BY(qs.total_worker_time / qs.execution_count) DESC

Steg 3: Uppdatera statistik

När du har identifierat de frågor som har den högsta CPU-förbrukningen uppdaterar du statistiken för de tabeller som används av dessa frågor. Du kan använda den sp_updatestats systemlagrade proceduren för att uppdatera statistiken för alla användardefinierade och interna tabeller i den aktuella databasen. Till exempel:

exec sp_updatestats

Obs!

Den sp_updatestats systemlagrade proceduren körs UPDATE STATISTICS mot alla användardefinierade och interna tabeller i den aktuella databasen. För regelbundet underhåll bör du se till att regelbundet schemalagt underhåll håller statistiken uppdaterad. Använd lösningar som Adaptive Index Defrag för att automatiskt hantera indexdefragmentering och statistikuppdateringar för en eller flera databaser. I den här proceduren väljs automatiskt om ett index återskapas eller omorganiseras enligt dess fragmenteringsnivå, bland andra parametrar, och uppdatera statistik med ett linjärt tröskelvärde.

Det finns mer information om sp_updatestats i sp_updatestats.

Om SQL Server fortfarande använder överdriven CPU-kapacitet går du till nästa steg.

Steg 4: Lägg till saknade index

Saknade index kan leda till att frågor körs långsammare och hög CPU-användning. Du kan identifiera saknade index och skapa dem för att förbättra prestandapåverkan.

  1. Kör följande fråga för att identifiera frågor som orsakar hög CPU-användning och som innehåller minst ett index som saknas i frågeplanen:

    -- Captures the Total CPU time spent by a query along with the query plan and total executions
    SELECT
        qs_cpu.total_worker_time / 1000 AS total_cpu_time_ms,
        q.[text],
        p.query_plan,
        qs_cpu.execution_count,
        q.dbid,
        q.objectid,
        q.encrypted AS text_encrypted
    FROM
        (SELECT TOP 500 qs.plan_handle,
         qs.total_worker_time,
         qs.execution_count FROM sys.dm_exec_query_stats qs ORDER BY qs.total_worker_time DESC) AS qs_cpu
    CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS q
    CROSS APPLY sys.dm_exec_query_plan(plan_handle) p
    WHERE p.query_plan.exist('declare namespace 
            qplan = "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
            //qplan:MissingIndexes')=1
    
  2. Granska körningsplanerna för de frågor som identifieras och finjustera frågan genom att göra nödvändiga ändringar. Följande skärmbild visar ett exempel där SQL Server pekar ut ett index som saknas för din fråga. Högerklicka på saknad indexdelen i frågeplanen och välj sedan Saknad indexinformation för att skapa indexet i ett annat fönster i SQL Server Management Studio.

    Skärmbild av körningsplanen med index som saknas.

  3. Använd följande fråga för att söka efter saknade index och tillämpa rekommenderade index som har höga måttvärden för förbättringar. Börja med de 5 eller 10 främsta rekommendationerna från utdata som har det högsta värdet för improvement_measure. Dessa index har den viktigaste positiva effekten på prestanda. Bestäm om du vill tillämpa dessa index och se till att prestandatestningen utförs för programmet. Fortsätt sedan att tillämpa rekommendationer för saknade index tills du uppnår önskade resultat för programmets prestanda. Mer information om det här avsnittet finns i Justera icke-klustrade index med förslag för saknade index.

    SELECT CONVERT(VARCHAR(30), GETDATE(), 126) AS runtime,
        mig.index_group_handle,
        mid.index_handle,
        CONVERT(DECIMAL(28, 1), migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans)) AS improvement_measure,
        'CREATE INDEX missing_index_' + CONVERT(VARCHAR, mig.index_group_handle) + '_' + CONVERT(VARCHAR, mid.index_handle) + ' ON ' + mid.statement + ' (' + ISNULL(mid.equality_columns,
            '') + CASE WHEN mid.equality_columns IS NOT NULL
    AND mid.inequality_columns IS NOT NULL THEN ','
    ELSE ''
    END + ISNULL(mid.inequality_columns,
            '') + ')' + ISNULL(' INCLUDE (' + mid.included_columns + ')',
            '') AS create_index_statement,
        migs.*,
        mid.database_id,
        mid.[object_id]
    FROM sys.dm_db_missing_index_groups mig
    INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle
    INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
    WHERE CONVERT (DECIMAL (28, 1),
                   migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans)) > 10
    ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC
    

Steg 5: Undersöka och lösa parameterkänsliga problem

Du kan använda kommandot DBCC FREEPROCCACHE för att frigöra plancachen och kontrollera om detta löser problemet med hög CPU-användning. Om problemet är åtgärdat är det en indikation på ett parameterkänsligt problem (PSP, även kallat "parametersniffningsproblem").

Obs!

Om du använder DBCC FREEPROCCACHE utan parametrarna tar du bort alla kompilerade planer från plancachen. Detta gör att nya frågekörningar kompileras igen, vilket leder till längre varaktighet en gång för varje ny fråga. Den bästa metoden är att använda DBCC FREEPROCCACHE ( plan_handle | sql_handle ) för att identifiera vilken fråga som kan orsaka problemet och sedan åtgärda den enskilda frågan eller frågorna.

Använd följande metoder för att minimera de parameterkänsliga problemen. Varje metod har associerade kompromisser och nackdelar.

  • Använd frågeledtråden Kompilera om. Du kan lägga till en RECOMPILE frågeledtråd till en eller flera av de frågor med hög CPU-användning som identifieras i steg 2. Den här ledtråden hjälper till att balansera den lilla ökningen av cpu-kompileringsanvändningen med en mer optimal prestanda för varje frågekörning. Mer information finns i Parametrar och återanvändning av körningsplan, Parameterkänslighet och Kompilera om-frågeledtråd.

    Här är ett exempel på hur du kan tillämpa ledtråden på din fråga.

    SELECT * FROM Person.Person 
    WHERE LastName = 'Wood'
    OPTION (RECOMPILE)
    
  • Använd frågeledtråden Optimera för för att åsidosätta det faktiska parametervärdet med ett mer typiskt parametervärde som täcker de flesta värdena i data. Det här alternativet kräver en fullständig förståelse av optimala parametervärden och associerade planegenskaper. Här är ett exempel på hur du använder den här ledtråden i din fråga.

    DECLARE @LastName Name = 'Frintu'
    SELECT FirstName, LastName FROM Person.Person 
    WHERE LastName = @LastName
    OPTION (OPTIMIZE FOR (@LastName = 'Wood'))
    
  • Använd frågeledtråden Optimera för okänd för att åsidosätta det faktiska parametervärdet med det genomsnittliga densitetsvektorvärdet. Du kan också göra detta genom att samla in inkommande parametervärden i lokala variabler och sedan använda de lokala variablerna i predikaten i stället för att använda själva parametrarna. För den här korrigeringen kan den genomsnittliga densiteten vara tillräcklig för att ge acceptabel prestanda.

  • Använd frågeledtråden DISABLE_PARAMETER_SNIFFING för att inaktivera parametersniffning helt. Här är ett exempel på hur du använder den i en fråga:

    SELECT * FROM Person.Address  
    WHERE City = 'SEATTLE' AND PostalCode = 98104
    OPTION (USE HINT ('DISABLE_PARAMETER_SNIFFING'))
    
  • Använd frågeledtråden KEEPFIXED PLAN för att förhindra omkompileringar i cacheminnet. Den här lösningen förutsätter att den "tillräckligt bra" gemensamma planen är den som redan finns i cacheminnet. Du kan också inaktivera automatiska statistikuppdateringar för att minska risken för att den bra planen tas bort och en ny dålig plan kompileras.

  • Använd kommandot DBCC FREEPROCCACHE som en tillfällig lösning tills programkoden har åtgärdats. Du kan använda kommandot DBCC FREEPROCCACHE (plan_handle) för att ta bort den plan som orsakar problemet. Om du till exempel vill hitta frågeplaner som refererar till tabellen Person.Person i AdventureWorks kan du använda den här frågan för att hitta frågereferensen. Sedan kan du släppa den specifika frågeplanen från cachen med hjälp av DBCC FREEPROCCACHE (plan_handle) som skapas i den andra kolumnen i frågeresultatet.

    SELECT text, 'DBCC FREEPROCCACHE (0x' + CONVERT(VARCHAR (512), plan_handle, 2) + ')' AS dbcc_freeproc_command FROM sys.dm_exec_cached_plans
    CROSS APPLY sys.dm_exec_query_plan(plan_handle)
    CROSS APPLY sys.dm_exec_sql_text(plan_handle)
    WHERE text LIKE '%person.person%'
    

Steg 6: Undersöka och lösa problem med SARGabilitet

Ett predikat i en fråga anses vara SARGable (Search ARGument-able) när motorn i SQL Server kan använda ett index för att påskynda körningen av frågan. Många frågedesigner förhindrar SARGability och leder till tabell- eller indexgenomsökningar och hög CPU-användning. Överväg följande fråga mot AdventureWorks-databasen där alla ProductNumber måste hämtas och funktionen SUBSTRING() som tillämpas på den, innan den jämförs med ett strängliteralt värde. Som du ser måste du hämta alla rader i tabellen först och sedan använda funktionen innan du kan göra en jämförelse. När du hämtar alla rader från tabellen innebär det en tabell- eller indexgenomsökning, vilket leder till högre CPU-användning.

SELECT ProductID, Name, ProductNumber
FROM [Production].[Product]
WHERE SUBSTRING(ProductNumber, 0, 4) =  'HN-'

Om du tillämpar en funktion eller beräkning på kolumnerna i sökpredikatet blir frågan vanligtvis icke-sargabel och leder till högre CPU-förbrukning. Lösningar omfattar vanligtvis att skriva om frågorna på ett kreativt sätt för att göra dem SARGable. En möjlig lösning på det här exemplet är den här omskrivningen där funktionen tas bort från frågepredikatet, en annan kolumn genomsöks och samma resultat uppnås:

SELECT ProductID, Name, ProductNumber
FROM [Production].[Product]
WHERE Name LIKE  'Hex%'

Här är ett annat exempel, där en säljchef kanske vill ge 10 % försäljningsprovision på stora beställningar och vill se vilka beställningar som har provisioner som är större än 300 USD. Här är det logiska, men icke-sargabla sättet att göra det på.

SELECT DISTINCT SalesOrderID, UnitPrice, UnitPrice * 0.10 [10% Commission]
FROM [Sales].[SalesOrderDetail]
WHERE UnitPrice * 0.10 > 300

Här är en möjlig mindre intuitiv men SARGable omskrivning av frågan, där beräkningen flyttas till andra sidan predikatet.

SELECT DISTINCT SalesOrderID, UnitPrice, UnitPrice * 0.10 [10% Commission]
FROM [Sales].[SalesOrderDetail]
WHERE UnitPrice > 300/0.10

SARGabilitet gäller inte bara för WHERE-satser, utan även för JOINs, HAVINGGROUP BY och ORDER BY-satser. Vanliga förekomster av skydd av SARGabilitet i frågor omfattar CONVERT(), CAST(), ISNULL(), COALESCE()-funktioner som används i WHERE eller JOIN-satser som leder till genomsökning av kolumner. I konverteringsfall av datatyp (CONVERT eller CAST) kan lösningen vara att se till att du jämför samma datatyper. Här är ett exempel där kolumnen T1.ProdID uttryckligen konverteras till datatypen INT i en JOIN. Konverteringen motverkar användningen av ett index i kopplingskolumnen. Samma problem uppstår med implicit konvertering där datatyperna är olika och SQL Server konverterar en av dem för att utföra kopplingen.

SELECT T1.ProdID, T1.ProdDesc
FROM T1 JOIN T2 
ON CONVERT(int, T1.ProdID) = T2.ProductID
WHERE t2.ProductID BETWEEN 200 AND 300

Om du vill undvika en genomsökning av tabellenT1 kan du ändra den underliggande datatypen för kolumnen ProdID efter korrekt planering och design och sedan koppla ihop de två kolumnerna utan att använda konverteringsfunktionen ON T1.ProdID = T2.ProductID.

En annan lösning är att skapa en beräknad kolumn i T1 som använder samma CONVERT() funktion och sedan skapa ett index på den. Detta gör att frågeoptimeraren kan använda indexet utan att du behöver ändra frågan.

ALTER TABLE dbo.T1  ADD IntProdID AS CONVERT (INT, ProdID);
CREATE INDEX IndProdID_int ON dbo.T1 (IntProdID);

I vissa fall kan frågor inte skrivas om enkelt för att möjliggöra SARGabilitet. I dessa fall kan du se om den beräknade kolumnen med ett index på den kan hjälpa, eller behålla frågan som den var med vetskapen om att den kan leda till högre CPU-scenarier.

Steg 7: Inaktivera tung spårning

Sök efter SQL-spårning eller XEvent-spårning som påverkar prestanda för SQL Server och orsakar hög CPU-användning. Om du till exempel använder följande händelser kan det orsaka hög CPU-användning om du spårar tung SQL Server-aktivitet:

  • XML-händelser för frågeplan (query_plan_profile, query_post_compilation_showplan, query_post_execution_plan_profile, query_post_execution_showplan, query_pre_execution_showplan)
  • Händelser på satsnivå (sql_statement_completed, sql_statement_starting, sp_statement_starting, sp_statement_completed)
  • Inloggnings- och utloggningshändelser (login, process_login_finish, login_event, logout)
  • Låshändelser (lock_acquired, lock_cancel, lock_released)
  • Väntehändelser (wait_info, wait_info_external)
  • SQL Granskningshändelser (beroende på vilken grupp som granskas och SQL Server-aktivitet i den gruppen)

Kör följande frågor för att identifiera aktiva XEvent- eller serverspårningar:

PRINT '--Profiler trace summary--'
SELECT traceid, property, CONVERT(VARCHAR(1024), value) AS value FROM::fn_trace_getinfo(
    default)
GO
PRINT '--Trace event details--'
SELECT trace_id,
    status,
    CASE WHEN row_number = 1 THEN path ELSE NULL end AS path,
    CASE WHEN row_number = 1 THEN max_size ELSE NULL end AS max_size,
    CASE WHEN row_number = 1 THEN start_time ELSE NULL end AS start_time,
    CASE WHEN row_number = 1 THEN stop_time ELSE NULL end AS stop_time,
    max_files,
    is_rowset,
    is_rollover,
    is_shutdown,
    is_default,
    buffer_count,
    buffer_size,
    last_event_time,
    event_count,
    trace_event_id,
    trace_event_name,
    trace_column_id,
    trace_column_name,
    expensive_event
FROM
    (SELECT t.id AS trace_id,
     row_number() over(PARTITION BY t.id order by te.trace_event_id, tc.trace_column_id) AS row_number,
     t.status,
     t.path,
     t.max_size,
     t.start_time,
     t.stop_time,
     t.max_files,
     t.is_rowset,
     t.is_rollover,
     t.is_shutdown,
     t.is_default,
     t.buffer_count,
     t.buffer_size,
     t.last_event_time,
     t.event_count,
     te.trace_event_id,
     te.name AS trace_event_name,
     tc.trace_column_id,
     tc.name AS trace_column_name,
     CASE WHEN te.trace_event_id in (23, 24, 40, 41, 44, 45, 51, 52, 54, 68, 96, 97, 98, 113, 114, 122, 146, 180) THEN CAST(1 as bit) ELSE CAST(0 AS BIT) END AS expensive_event FROM sys.traces t CROSS APPLY::fn_trace_geteventinfo(t.id) AS e JOIN sys.trace_events te ON te.trace_event_id = e.eventid JOIN sys.trace_columns tc ON e.columnid = trace_column_id) AS x
GO
PRINT '--XEvent Session Details--'
SELECT sess.NAME 'session_name', event_name, xe_event_name, trace_event_id,
    CASE WHEN xemap.trace_event_id IN(23, 24, 40, 41, 44, 45, 51, 52, 54, 68, 96, 97, 98, 113, 114, 122, 146, 180) 
    THEN Cast(1 AS BIT)
ELSE Cast(0 AS BIT)
END AS expensive_event
FROM sys.dm_xe_sessions sess
JOIN sys.dm_xe_session_events evt
ON sess.address = evt.event_session_address
INNER JOIN sys.trace_xe_event_map xemap
ON evt.event_name = xemap.xe_event_name
GO

Steg 8: Åtgärda hög CPU-användning som orsakas av spinlockkonkurration

Information om hur du löser vanlig hög CPU-användning som orsakas av spinlockkonkurrens finns i följande avsnitt.

SOS_CACHESTORE spinlockkonkurration

Om din SQL Server-instans upplever hård SOS_CACHESTORE spinlockkonkurration eller om du märker att dina frågeplaner ofta tas bort för oplanerade frågearbetsbelastningar kan du läsa följande artikel och aktivera spårningsflaggan T174DBCC TRACEON (174, -1) med hjälp av kommandot :

Korrigering: SOS_CACHESTORE spinlockkonkurrens på ad hoc-SQL Server plancache orsakar hög CPU-användning i SQL Server.

Om villkoret med hög CPU-användning har lösts med hjälp av T174 aktiverar du det som en startparameter med hjälp av Konfigurationshanteraren för SQL Server.

Slumpmässig hög CPU-användning på grund av SOS_BLOCKALLOCPARTIALLIST spinlockkonkurration på datorer med stort minne

Om din SQL Server instans upplever slumpmässig hög CPU-användning på grund av SOS_BLOCKALLOCPARTIALLIST spinlockkonkurration rekommenderar vi att du tillämpar kumulativ uppdatering 21 för SQL Server 2019. Mer information om hur du löser problemet finns i felreferensen 2410400 och DBCC DROPCLEANBUFFERS som ger tillfällig åtgärd.

Hög CPU-användning på grund av spinlockkonkurration på XVB_list på avancerade datorer

Om din SQL Server-instans upplever ett scenario med hög CPU-användning som orsakas av spinlockkonkurrens på XVB_LIST spinlocken på datorer med hög konfiguration (avancerade system med ett stort antal nyare processorer) aktiverar du spårningsflaggan TF8102 tillsammans med TF8101.

Obs!

Hög CPU-användning kan bero på spinlockkonkurration på många andra spinlocktyper. Mer information om spinlock finns i Diagnostisera och lösa spinlockkonkurration på SQL Server.

Steg 9: Konfigurera din virtuella dator

Om du använder en virtuell dator kontrollerar du att du inte överetablerar CPU:er och att de är korrekt konfigurerade. Mer information finns i Felsöka prestandaproblem för virtuella ESX/ESXi-datorer (2001003).

Steg 10: Skala upp systemet för att använda fler CPU:er

Om enskilda frågeinstanser använder lite CPU-kapacitet, men den övergripande arbetsbelastningen för alla frågor tillsammans orsakar hög CPU-förbrukning, bör du överväga att skala upp datorn genom att lägga till fler processorer. Använd följande fråga för att hitta antalet frågor som har överskridit ett visst tröskelvärde för genomsnittlig och maximal CPU-förbrukning per körning och som har körts många gånger i systemet (se till att du ändrar värdena för de två variablerna så att de matchar din miljö):

-- Shows queries where Max and average CPU time exceeds 200 ms and executed more than 1000 times
DECLARE @cputime_threshold_microsec INT = 200*1000
DECLARE @execution_count INT = 1000
SELECT qs.total_worker_time/1000 total_cpu_time_ms,
       qs.max_worker_time/1000 max_cpu_time_ms,
       (qs.total_worker_time/1000)/execution_count average_cpu_time_ms,
       qs.execution_count,
       q.[text]
FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS q
WHERE (qs.total_worker_time/execution_count > @cputime_threshold_microsec
        OR qs.max_worker_time > @cputime_threshold_microsec )
        AND execution_count > @execution_count
ORDER BY  qs.total_worker_time DESC 

Se även