Optimiser l'utilisation élevée du processeur dans les instances

Ce document explique comment examiner et optimiser une instance Cloud SQL pour SQL Server si cette instance est identifiée par l'outil de recommandation d'instances sous-provisionnée comme ayant une utilisation élevée du processeur.

Si le vCPU d'une instance n'est pas correctement dimensionné, il peut devenir une source de conflit. Pour vérifier si le processeur est un goulot d'étranglement ou sous-provisionné, utilisez les requêtes de ce document.

Vérifier le nombre moyen de tâches

Exécutez cette requête plusieurs fois pour vérifier le nombre moyen de tâches. Si le nombre moyen de tâches est systématiquement élevé, l'instance est peut-être confrontée à une pression du processeur.


SELECT AVG(current_tasks_count) AS [Avg Task Count],
AVG(work_queue_count) AS [Avg Work Queue Count],
AVG(runnable_tasks_count) AS [Avg Runnable Task Count],
AVG(pending_disk_io_count) AS [Avg Pending DiskIO Count],
GETDATE() AS [System Time]
FROM sys.dm_os_schedulers WITH (NOLOCK)
WHERE scheduler_id < 255 OPTION (RECOMPILE);

Déterminer s'il est nécessaire d'ajouter des processeurs virtuels

Dans certaines conditions, vous pouvez augmenter le processeur virtuel. Utilisez cette requête pour déterminer s'il est nécessaire d'ajouter des processeurs virtuels.


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

Rechercher les index manquants

Recherchez les index manquants à l'aide de la requête suivante. Testez ces index sur une instance hors production pour voir comment ils affectent les performances du processeur.


SELECT
CONVERT(
  decimal(18, 2), migs.user_seeks * migs.avg_total_user_cost * (migs.avg_user_impact * 0.01))
  AS [index_advantage],
CONVERT(nvarchar(25), migs.last_user_seek, 20) AS [last_user_seek],
mid.[statement] AS [Database.Schema.Table],
COUNT(1) OVER (PARTITION BY mid.[statement]) AS [missing_indexes_for_table],
COUNT(1)
  OVER (PARTITION BY mid.[statement], mid.equality_columns)
  AS [similar_missing_indexes_for_table],
mid.equality_columns,
mid.inequality_columns,
mid.included_columns,
migs.user_seeks,
CONVERT(decimal(18, 2), migs.avg_total_user_cost) AS [avg_total_user_cost],
migs.avg_user_impact
FROM sys.dm_db_missing_index_group_stats AS migs WITH(NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH(NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH(NOLOCK)
ON mig.index_handle = mid.index_handle
ORDER BY index_advantage DESC

Rechercher les index ayant trop de surcharge

L'ajout d'un index peut contribuer à l'optimisation, mais peut également alourdir les performances, ce qui contribue à une utilisation plus élevée du processeur et de la mémoire. Examinez les index renvoyés qui présentent un nombre très élevé d'écritures par rapport à un très petit nombre de lectures et envisagez de les supprimer.


SELECT
 SCHEMA_NAME(o.[schema_id]) AS [Schema Name],
 OBJECT_NAME(s.[object_id]) AS [TABLE Name],
 i.name AS [Index Name],
 i.index_id,
 i.is_disabled,
 i.is_hypothetical,
 i.has_filter,
 i.fill_factor,
 s.user_updates AS [Total Writes],
 s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads],
 s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference]
FROM sys.dm_db_index_usage_stats AS s WITH(NOLOCK)
INNER JOIN sys.indexes AS i WITH(NOLOCK) ON s.[object_id] = i.[object_id]
AND i.index_id = s.index_id
INNER JOIN sys.objects AS o WITH(NOLOCK) ON i.[object_id] = o.[object_id]
WHERE
 OBJECTPROPERTY(s.[object_id], 'IsUserTable') = 1
 AND s.database_id = DB_ID()
 AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups)
 AND i.index_id > 1
 AND i.[type_desc] = N'NONCLUSTERED'
 AND i.is_primary_key = 0
 AND i.is_unique_constraint = 0
 AND i.is_unique = 0
ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC

Identifier les requêtes qui consomment le plus en ressources de processeur

Examinez les 20 requêtes les plus fréquentes en fonction de l'utilisation du processeur ou du temps de calcul. Il s'agit des requêtes basées sur les statistiques d'exécution des requêtes qui utilisent la plus grande partie du processeur. Ces statistiques sont agrégées au fil du temps et sont liées aux plans du cache.


SELECT
top 20
SUBSTRING(qt.TEXT, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.TEXT)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1),
qs.execution_count,
qs.total_logical_reads, qs.last_logical_reads,
qs.total_logical_writes, qs.last_logical_writes,
qs.total_worker_time,
qs.last_worker_time,
qs.total_elapsed_time/1000000 total_elapsed_time_in_S,
qs.last_elapsed_time/1000000 last_elapsed_time_in_S,
qs.last_execution_time,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY qs.total_worker_time DESC -- CPU time

Rechercher les conversions implicites dans les plans de requête

Cette opération est coûteuse et s'affiche généralement en tant qu'avertissement dans le plan d'exécution de la requête. Le message comporte généralement un avertissement indiquant qu'il peut affecter l'estimation de la cardinalité dans le choix du plan de requête. Vous pouvez facilement identifier les conversions implicites lorsque vous consultez les plans de requête dans SQL Server Management Studio (SSMS).