Al ejecutar nuestro ERP corporativo (Dynamics AX 2012), noté que nuestro entorno de producción parecía mucho más lento que nuestros sistemas de desarrollo.
Después de realizar las mismas actividades tanto en el entorno de desarrollo como en el de producción mientras ejecutaba un seguimiento, confirmó que las consultas SQL se ejecutaban muy lentamente en nuestro entorno de producción en comparación con el desarrollo (10-50 veces más lento en promedio).
Al principio, atribuí esto a la carga, volví a ejecutar las mismas actividades en el entorno de producción durante las horas libres y encontré los mismos resultados en el seguimiento.
Borré mis estadísticas de espera en SQL Server, luego dejé que el servidor se ejecutara bajo su carga de producción normal durante un tiempo y luego ejecuté esta consulta:
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
Mis resultados son los siguientes:
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
Aparentemente, la espera más grande es SOS_Scheduler_Yield por mucho tiempo, y busqué en Google y descubrí que generalmente se relaciona con que la CPU no puede mantenerse al día.
Luego ejecuté esta consulta varias veces seguidas.
SELECT *
FROM sys.dm_os_schedulers
WHERE scheduler_id < 255
Sé que se supone que debo estar buscando programadores con runnable_tasks_count o pendientes_disk_io_count distintos de cero, pero es básicamente cero casi todo el tiempo.
También debo mencionar que el Grado máximo de paralelismo se estableció en 1, ya que la carga de trabajo de Dynamics AX es típicamente de naturaleza OLTP, y cambiarla 8 no hizo mucha diferencia en las estadísticas de espera anteriores, se volvieron casi exactamente iguales con el mismo problemas de rendimiento
No sé a dónde ir desde aquí, básicamente tengo un servidor SQL que aparentemente está atorado por la CPU pero no espera runnable_tasks o IO.
Sé que el subsistema IO de este SQL Server no es muy bueno, porque ejecutar SQLIO en la unidad que contiene las bases de datos reales puede generar números bastante bajos (piense 10 MB por segundo para ciertos tipos de lecturas / escrituras), dicho eso, no parece que SQL esté esperando eso debido a la cantidad de memoria en el servidor que almacena en caché la mayoría de las bases de datos.
Aquí hay información del entorno para ayudar:
Entorno de producción:
- servidor SQL
- HP ProLian DL360p Gen8
- Intel Xeon E5-2650 0 @ 2.00GHz x 2 con hyperthreading (32 núcleos lógicos)
- 184 GB de memoria
- Windows Server 2012
- 2 instancias de SQL Server 2012 Standard (RTM, sin parchear)
- Raid 1 279GB de unidades (15k) C: unidad, contiene bases de datos y sistema operativo
- Archivo de página y TempDB en unidades distintas y separadas (estado sólido)
Mi DEV:
- Servidor SQL alojado Hyper-V y servidor AOS Dynamics AX 2012
- Core i7 3.4ghz con hyperthreading (8 núcleos lógicos)
- 8GB de memoria
- Windows Server 2008 R2
- SSD para toda la VM.
Agradecería cualquier aportación sobre otras cosas a tener en cuenta.