En exécutant notre ERP d'entreprise (Dynamics AX 2012), j'ai remarqué que notre environnement de production semblait beaucoup plus lent que nos systèmes de développement.
Après avoir effectué les mêmes activités dans les environnements de développement et de production tout en exécutant une trace, j'ai confirmé que les requêtes SQL s'exécutaient très lentement sur notre environnement de production par rapport au développement (10 à 50 fois plus lent en moyenne).
Au début, j'ai attribué cela à la charge, puis j'ai relancé les mêmes activités sur l'environnement de production pendant les heures creuses et j'ai trouvé les mêmes résultats dans la trace.
J'ai effacé mes statistiques d'attente dans SQL Server, puis j'ai laissé le serveur fonctionner sous sa charge de production normale pendant un petit moment, puis j'ai exécuté cette requête:
WITH [Waits] AS
(SELECT
[wait_type],
[wait_time_ms] / 1000.0 AS [WaitS],
([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS],
[signal_wait_time_ms] / 1000.0 AS [SignalS],
[waiting_tasks_count] AS [WaitCount],
100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage],
ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum]
FROM sys.dm_os_wait_stats
WHERE [wait_type] NOT IN (
N'CLR_SEMAPHORE', N'LAZYWRITER_SLEEP',
N'RESOURCE_QUEUE', N'SQLTRACE_BUFFER_FLUSH',
N'SLEEP_TASK', N'SLEEP_SYSTEMTASK',
N'WAITFOR', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
N'CHECKPOINT_QUEUE', N'REQUEST_FOR_DEADLOCK_SEARCH',
N'XE_TIMER_EVENT', N'XE_DISPATCHER_JOIN',
N'LOGMGR_QUEUE', N'FT_IFTS_SCHEDULER_IDLE_WAIT',
N'BROKER_TASK_STOP', N'CLR_MANUAL_EVENT',
N'CLR_AUTO_EVENT', N'DISPATCHER_QUEUE_SEMAPHORE',
N'TRACEWRITE', N'XE_DISPATCHER_WAIT',
N'BROKER_TO_FLUSH', N'BROKER_EVENTHANDLER',
N'FT_IFTSHC_MUTEX', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
N'DIRTY_PAGE_POLL', N'SP_SERVER_DIAGNOSTICS_SLEEP')
)
SELECT
[W1].[wait_type] AS [WaitType],
CAST ([W1].[WaitS] AS DECIMAL(14, 2)) AS [Wait_S],
CAST ([W1].[ResourceS] AS DECIMAL(14, 2)) AS [Resource_S],
CAST ([W1].[SignalS] AS DECIMAL(14, 2)) AS [Signal_S],
[W1].[WaitCount] AS [WaitCount],
CAST ([W1].[Percentage] AS DECIMAL(4, 2)) AS [Percentage],
CAST (([W1].[WaitS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgWait_S],
CAST (([W1].[ResourceS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgRes_S],
CAST (([W1].[SignalS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgSig_S]
FROM [Waits] AS [W1] INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum]
GROUP BY [W1].[RowNum], [W1].[wait_type], [W1].[WaitS],
[W1].[ResourceS], [W1].[SignalS], [W1].[WaitCount], [W1].[Percentage]
HAVING SUM ([W2].[Percentage]) - [W1].[Percentage] < 95; -- percentage threshold
Mes résultats sont les suivants:
WaitType Wait_S Resource_S Signal_S WaitCount Percentage AvgWait_S AvgRes_S AvgSig_S
SOS_SCHEDULER_YIELD 4162.52 3.64 4158.88 4450085 77.33 0.0009 0.0000 0.0009
ASYNC_NETWORK_IO 457.98 331.59 126.39 351113 8.51 0.0013 0.0009 0.0004
PAGELATCH_EX 252.94 5.14 247.80 796348 4.70 0.0003 0.0000 0.0003
WRITELOG 166.01 48.01 118.00 302209 3.08 0.0005 0.0002 0.0004
LCK_M_U 145.47 145.45 0.02 123 2.70 1.1827 1.1825 0.0002
Donc, apparemment, la plus grande attente est de loin SOS_Scheduler_Yield, et j'ai recherché sur Google et j'ai constaté que cela concernait généralement le processeur qui ne pouvait pas suivre.
J'ai ensuite exécuté cette requête plusieurs fois de suite.
SELECT *
FROM sys.dm_os_schedulers
WHERE scheduler_id < 255
Je sais que je suis censé rechercher des ordonnanceurs avec runnable_tasks_count ou zero_disk_io_count différent de zéro, mais c'est pratiquement zéro presque tout le temps.
Je dois également mentionner que Max Degree of Parallelism a été défini sur 1, car la charge de travail de Dynamics AX est généralement de nature OLTP, et le changer 8 n'a pas fait beaucoup de différence dans les statistiques d'attente ci-dessus, elles sont devenues presque exactement les mêmes avec le même problèmes de performances.
Je ne sais pas où aller à partir d'ici, j'ai essentiellement un serveur SQL qui semble limité, mais n'attend pas sur runnable_tasks ou IO.
Je sais que le sous-système d'E / S de ce serveur SQL n'est pas très bon, car l'exécution de SQLIO sur le lecteur contenant les bases de données réelles peut conduire à des nombres assez faibles (pensez à 10 Mo par seconde pour certains types de lectures / écritures), cela dit, il ne semble pas que SQL attend cela à cause de la quantité de mémoire sur le serveur qui met en cache la plupart des bases de données.
Voici quelques informations sur l'environnement pour vous aider:
Environnement de production:
- serveur SQL
- HP ProLian DL360p Gen8
- Intel Xeon E5-2650 0 @ 2,00 GHz x 2 avec hyperthreading (32 cœurs logiques)
- 184 Go de mémoire
- Windows Server 2012
- 2 instances de SQL Server 2012 Standard (RTM, non corrigé)
- Raid 1 disques de 279 Go (15k) disque C: contient les bases de données et le système d'exploitation
- Fichier d'échange et TempDB sur des lecteurs distincts et séparés (état solide)
Mon DEV:
- Hyper-V hébergé SQL Server et serveur Dynamics AX 2012 AOS
- Core i7 3.4ghz avec hyperthreading (8 cœurs logiques)
- 8 Go de mémoire
- Windows Server 2008 R2
- SSD pour la VM entière.
Je serais heureux de recevoir toute contribution sur d'autres choses à rechercher.