Als wir unser Unternehmens-ERP (Dynamics AX 2012) ausführten, stellte ich fest, dass unsere Produktionsumgebung viel langsamer schien als unsere Entwicklungssysteme.
Nachdem ich die gleichen Aktivitäten sowohl in der Entwicklungs- als auch in der Produktionsumgebung ausgeführt habe, während ein Trace ausgeführt wurde, bestätigte ich, dass SQL-Abfragen in unserer Produktionsumgebung im Vergleich zur Entwicklung sehr langsam ausgeführt wurden (durchschnittlich 10-50x langsamer).
Zuerst schrieb ich dies dem Laden zu und führte die gleichen Aktivitäten in der Produktionsumgebung außerhalb der Geschäftszeiten erneut aus und fand die gleichen Ergebnisse in der Ablaufverfolgung.
Ich habe meine Wartestatistiken in SQL Server gelöscht und den Server eine Weile unter normaler Produktionslast laufen lassen und dann die folgende Abfrage ausgeführt:
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
Meine Ergebnisse sind wie folgt:
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
Die mit Abstand größte Wartezeit scheint also SOS_Scheduler_Yield zu sein, und ich habe herumgegoogelt und festgestellt, dass dies in der Regel damit zusammenhängt, dass die CPU nicht mithalten kann.
Ich habe diese Abfrage dann mehrmals hintereinander ausgeführt.
SELECT *
FROM sys.dm_os_schedulers
WHERE scheduler_id < 255
Ich weiß, dass ich nach Schedulern suchen soll, die nicht null sind. Runnable_tasks_count oder pending_disk_io_count, aber im Grunde ist es fast die ganze Zeit null.
Ich sollte auch erwähnen, dass Max. Grad der Parallelität auf 1 gesetzt wurde, da die Dynamics AX-Arbeitslast normalerweise OLTP ist und die Änderung von 8 keinen großen Unterschied in den obigen Wartestatistiken machte Leistungsprobleme.
Ich bin irgendwie ratlos, wo ich von hier aus hingehen soll. Ich habe im Grunde einen SQL Server, der anscheinend überlastet ist, aber nicht auf runnable_tasks oder IO wartet.
Ich weiß, dass das E / A-Subsystem dieses SQL Servers nicht sehr gut ist, da das Ausführen von SQLIO auf dem Laufwerk, das die tatsächlichen Datenbanken enthält, zu ziemlich niedrigen Zahlen führen kann (denken Sie an 10 MB pro Sekunde für bestimmte Arten von Lese- / Schreibvorgängen). SQL scheint nicht darauf zu warten, da auf dem Server die meisten Datenbanken zwischengespeichert sind.
Hier sind einige Umgebungsinformationen, die helfen sollen:
Produktionsumgebung:
- SQL Server
- HP ProLian DL360p Gen8
- Intel Xeon E5-2650 0 bei 2,00 GHz x 2 mit Hyperthreading (32 logische Kerne)
- 184 GB Speicher
- Windows Server 2012
- 2 Instanzen von SQL Server 2012 Standard (RTM, nicht gepatcht)
- RAID 1 279 GB-Laufwerke (15 KB) C: Laufwerk, enthält Datenbanken und Betriebssystem
- Auslagerungsdatei und TempDB auf getrennten Laufwerken (Solid State)
Mein DEV:
- Von Hyper-V gehosteter SQL Server- und Dynamics AX 2012-AOS-Server
- Core i7 3.4 GHz mit Hyperthreading (8 logische Kerne)
- 8 GB Speicher
- Windows Server 2008 R2
- SSD für die gesamte VM.
Ich würde mich über jede Eingabe zu anderen Themen freuen.