Wait statistics
Đa phần sử dụng kỹ thuật này để dò tìm các truy vấn đang hold lock trong hệ thống. Ngoài ra kỹ thuật này được dùng thường xuyên để đánh giá hiệu năng chung cho: CPU, I/O, Network,…
Bài toán thực tế
Trong hệ thống OLTP database của SDS thường gặp các phản hồi bất thường (tức là chưa có cảnh báo từ trước), thì để dò xét nguyên nhân, một trong các cách có thể dùng là dựa vào built-in DMV wait.
Các nguyên nhân thường gặp:
- Các query đang bị block (do một tiến trình/query khác đang lock tài nguyên);
- Tiến trình đồng bộ transaction log (giữa các node của AAG) đang thực hiện;
- Các ứng dụng xử lý dữ liệu trả về quá chậm, dẫn đến thời gian hold lock quá lâu…
Các built-in DMV này cung cấp các thông tin chủ yếu liên quan đến các Wait Type (có thể hiểu nôm na là các trường hợp mà 1 tiến trình phải chờ, vd: chờ lấy lock), mà dựa vào các thông tin này chúng ta có thể biết được query, tiến trình nào đang gây lock hay các vấn đề liên quan đến network, disk I/O, memory, CPU, AAG…
2 DMV sử dụng ở đây: sys.dm_os_waiting_tasks
, sys.dm_os_waiting_stats
Một chút lý thuyết cơ bản liên quan
Nói về lý thuyết một chút trước khi giới thiệu về 2 DMV trên, để hiểu rõ hơn nguồn gốc của các sự kiên wait trong SQL Server, cũng như tại sao chúng ta lại cần 2 DMV trên.
Khi có 1 request tạo connection từ client, SQLServer auth client, tạo connection và trả về session_id
cho client. Kể từ đó client có thể bắt đầu tạo request, ví dụ như truy vấn dữ liệu. Ngay khi nhận request, SQLServer tạo task để bắt đầu xử lý.
Hình dưới đây mô tả ở mức thấp quá trình SQL Server xử lý cho 1 request:
- Các task sẽ được thực thi trên
worker_thread
mà hệ điều hành cấp cho SQLServer. SQLServer quản lý cácworker_thread
này thông qua thread pool. - Việc quyết định một task sẽ dùng (một-hay nhiều)
worker_thread
nào được điều khiển bằngSQLOS Scheduler
(engine của SQLServer). - Tùy vào độ phức tạp, Task cần thực hiện có thể được chia nhỏ thành nhiều sub-task và được thực thi trên nhiều
worker_thread
(đây chính là khả năng tính toán song song của SQLServer). - Thông thường, số lượng
Scheduler
sẽ tương ứng với số CPU core của OS (8-core CPU -> 8 SQLOS scheduler). Chúng ta có thể cấu hình, customize như ở đây…). Tại 1 thời điểm, chỉ có 1worker_thread
được phép chạy trên 1 CPU.
Một thread chỉ có thể tồn tại ở 1 trong 3 trạng thái sau:
RUNNING
: đang chạy trên CPUSUSPENDED
: khi thread cần tài nguyên (resource), ví dụ dữ liệu trên memory; thread sẽ được đẩy vàowaiter_list
, và trạng thái chuyển thànhSUSPENDED
, cho đến khi resource đó sẵn sàng (ví dụ như lock trên data được release)RUNNABLE
: nếu thread không cần tài nguyên, nhưng trong thời điểm đóscheduler
đang xử lý một thread khác. Khi đó thread ban đầu sẽ được đưa vàorunnable_queue
và có trạng thái làRUNNABLE
.
Hình dưới đây mô tả vòng đời trạng thái của thread:
Như ở ví dụ trên:
Session 55
có trạng thái làRUNNING
vì đang được chạy trên CPU;Session 52
không cần tài nguyên, nhưng doSession 55
đang chạy nên phải chờ ởrunnable_queue
, và có trạng thái làRUNNABLE
;Session 53
đang chờ lấy lockLCK_M_S
nên nó có trạng tháiSUSPENDED
, và được xếp ởwaiter_list
(LockLCK_M_S
là lock để read resource).
Chúng ta quan tâm đến 2 giá trị thời gian:
- SQLOS theo dõi thời gian 1 thread tồn tại ở trạng thái
SUSPENDED
(trongwaiter_list
cho đến khi được chuyển sangrunnable_queue
), gọi làresource_time
. - Tương tự, thời gian 1 thread tồn tại ở trạng thái
RUNNABLE
cho đến khi CPU thông báo (signal) và cho chạy, gọi làsignal_wait
. Có thể hiểu nôm na đây chính là thời gian chờ CPU.
Và như thế, thời gian để 1 thread bắt đầu được xử lý đến khi thực hiện ở CPU chính là total_wait_time
= resource_wait
+ signal_wait
.
3 chỉ số trên là 1 trong những yếu tố chính từ kết quả trả về từ 2 built-in DMV mà chúng ta sẽ sử dụng sau đây: sys.dm_os_waiting_tasks
, sys.dm_os_waiting_stats
.
Kiểm tra các sự kiện đang wait ở thời điểm hiện tại (real time)
sys.dm_os_waiting_tasks
Sử dụng query sau, để có thể lấy ra được cả nội dung các truy vấn:
SELECT blocking.session_id AS blocking_session_id,
blocked.session_id AS blocked_session_id,
waitstats.wait_type AS blocking_resource,
waitstats.wait_duration_ms,
waitstats.resource_description,
blocked_cache.text AS blocked_text,
blocking_cache.text AS blocking_text
FROM sys.dm_exec_connections AS blocking
INNER JOIN sys.dm_exec_requests blocked ON blocking.session_id = blocked.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(blocked.sql_handle) blocked_cache
CROSS APPLY sys.dm_exec_sql_text(blocking.most_recent_sql_handle) blocking_cache
INNER JOIN sys.dm_os_waiting_tasks waitstats ON waitstats.session_id = blocked.session_id;
Lưu ý kết quả trả về sẽ là các transaction đang block các transaction khác ở thời điểm hiện tại (real-time).
Kết quả này cũng tương tự như khi chúng ta sử dụng query ở bài viết này
Trong ví dụ trên, session 51
đang nắm khóa (wait_type) LCK_M_S
, và session 56
đã bị block.
Từ đây ta có thể tìm cách tuning để session 51
thực hiện nhanh hơn,…
Kiểm tra lịch sử, toàn bộ wait để dò tìm bottlenecks
sys.dm_os_waiting_stats
Dynamic View này trả về giá trị tích lũy của tất cả wait_type
kể từ lần gần nhất SQLServer restart.
Ta xem xét kết quả trả về từ query sau (đã loại bỏ các wait_type
thường không phải là vấn đề hiệu năng):
-- Last updated October 1, 2021
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 (
-- These wait types are almost 100% never a problem and so they are
-- filtered out to avoid them skewing the results. Click on the URL
-- for more information.
N'BROKER_EVENTHANDLER', -- https://www.sqlskills.com/help/waits/BROKER_EVENTHANDLER
N'BROKER_RECEIVE_WAITFOR', -- https://www.sqlskills.com/help/waits/BROKER_RECEIVE_WAITFOR
N'BROKER_TASK_STOP', -- https://www.sqlskills.com/help/waits/BROKER_TASK_STOP
N'BROKER_TO_FLUSH', -- https://www.sqlskills.com/help/waits/BROKER_TO_FLUSH
N'BROKER_TRANSMITTER', -- https://www.sqlskills.com/help/waits/BROKER_TRANSMITTER
N'CHECKPOINT_QUEUE', -- https://www.sqlskills.com/help/waits/CHECKPOINT_QUEUE
N'CHKPT', -- https://www.sqlskills.com/help/waits/CHKPT
N'CLR_AUTO_EVENT', -- https://www.sqlskills.com/help/waits/CLR_AUTO_EVENT
N'CLR_MANUAL_EVENT', -- https://www.sqlskills.com/help/waits/CLR_MANUAL_EVENT
N'CLR_SEMAPHORE', -- https://www.sqlskills.com/help/waits/CLR_SEMAPHORE
-- Maybe comment this out if you have parallelism issues
N'CXCONSUMER', -- https://www.sqlskills.com/help/waits/CXCONSUMER
-- Maybe comment these four out if you have mirroring issues
N'DBMIRROR_DBM_EVENT', -- https://www.sqlskills.com/help/waits/DBMIRROR_DBM_EVENT
N'DBMIRROR_EVENTS_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_EVENTS_QUEUE
N'DBMIRROR_WORKER_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_WORKER_QUEUE
N'DBMIRRORING_CMD', -- https://www.sqlskills.com/help/waits/DBMIRRORING_CMD
N'DIRTY_PAGE_POLL', -- https://www.sqlskills.com/help/waits/DIRTY_PAGE_POLL
N'DISPATCHER_QUEUE_SEMAPHORE', -- https://www.sqlskills.com/help/waits/DISPATCHER_QUEUE_SEMAPHORE
N'EXECSYNC', -- https://www.sqlskills.com/help/waits/EXECSYNC
N'FSAGENT', -- https://www.sqlskills.com/help/waits/FSAGENT
N'FT_IFTS_SCHEDULER_IDLE_WAIT', -- https://www.sqlskills.com/help/waits/FT_IFTS_SCHEDULER_IDLE_WAIT
N'FT_IFTSHC_MUTEX', -- https://www.sqlskills.com/help/waits/FT_IFTSHC_MUTEX
-- Maybe comment these six out if you have AG issues
N'HADR_CLUSAPI_CALL', -- https://www.sqlskills.com/help/waits/HADR_CLUSAPI_CALL
N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', -- https://www.sqlskills.com/help/waits/HADR_FILESTREAM_IOMGR_IOCOMPLETION
N'HADR_LOGCAPTURE_WAIT', -- https://www.sqlskills.com/help/waits/HADR_LOGCAPTURE_WAIT
N'HADR_NOTIFICATION_DEQUEUE', -- https://www.sqlskills.com/help/waits/HADR_NOTIFICATION_DEQUEUE
N'HADR_TIMER_TASK', -- https://www.sqlskills.com/help/waits/HADR_TIMER_TASK
N'HADR_WORK_QUEUE', -- https://www.sqlskills.com/help/waits/HADR_WORK_QUEUE
N'KSOURCE_WAKEUP', -- https://www.sqlskills.com/help/waits/KSOURCE_WAKEUP
N'LAZYWRITER_SLEEP', -- https://www.sqlskills.com/help/waits/LAZYWRITER_SLEEP
N'LOGMGR_QUEUE', -- https://www.sqlskills.com/help/waits/LOGMGR_QUEUE
N'MEMORY_ALLOCATION_EXT', -- https://www.sqlskills.com/help/waits/MEMORY_ALLOCATION_EXT
N'ONDEMAND_TASK_QUEUE', -- https://www.sqlskills.com/help/waits/ONDEMAND_TASK_QUEUE
N'PARALLEL_REDO_DRAIN_WORKER', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_DRAIN_WORKER
N'PARALLEL_REDO_LOG_CACHE', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_LOG_CACHE
N'PARALLEL_REDO_TRAN_LIST', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_TRAN_LIST
N'PARALLEL_REDO_WORKER_SYNC', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_SYNC
N'PARALLEL_REDO_WORKER_WAIT_WORK', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_WAIT_WORK
N'PREEMPTIVE_OS_FLUSHFILEBUFFERS', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_OS_FLUSHFILEBUFFERS
N'PREEMPTIVE_XE_GETTARGETSTATE', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_XE_GETTARGETSTATE
N'PVS_PREALLOCATE', -- https://www.sqlskills.com/help/waits/PVS_PREALLOCATE
N'PWAIT_ALL_COMPONENTS_INITIALIZED', -- https://www.sqlskills.com/help/waits/PWAIT_ALL_COMPONENTS_INITIALIZED
N'PWAIT_DIRECTLOGCONSUMER_GETNEXT', -- https://www.sqlskills.com/help/waits/PWAIT_DIRECTLOGCONSUMER_GETNEXT
N'PWAIT_EXTENSIBILITY_CLEANUP_TASK', -- https://www.sqlskills.com/help/waits/PWAIT_EXTENSIBILITY_CLEANUP_TASK
N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', -- https://www.sqlskills.com/help/waits/QDS_PERSIST_TASK_MAIN_LOOP_SLEEP
N'QDS_ASYNC_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_ASYNC_QUEUE
N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP',
-- https://www.sqlskills.com/help/waits/QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP
N'QDS_SHUTDOWN_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_SHUTDOWN_QUEUE
N'REDO_THREAD_PENDING_WORK', -- https://www.sqlskills.com/help/waits/REDO_THREAD_PENDING_WORK
N'REQUEST_FOR_DEADLOCK_SEARCH', -- https://www.sqlskills.com/help/waits/REQUEST_FOR_DEADLOCK_SEARCH
N'RESOURCE_QUEUE', -- https://www.sqlskills.com/help/waits/RESOURCE_QUEUE
N'SERVER_IDLE_CHECK', -- https://www.sqlskills.com/help/waits/SERVER_IDLE_CHECK
N'SLEEP_BPOOL_FLUSH', -- https://www.sqlskills.com/help/waits/SLEEP_BPOOL_FLUSH
N'SLEEP_DBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DBSTARTUP
N'SLEEP_DCOMSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DCOMSTARTUP
N'SLEEP_MASTERDBREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERDBREADY
N'SLEEP_MASTERMDREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERMDREADY
N'SLEEP_MASTERUPGRADED', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERUPGRADED
N'SLEEP_MSDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_MSDBSTARTUP
N'SLEEP_SYSTEMTASK', -- https://www.sqlskills.com/help/waits/SLEEP_SYSTEMTASK
N'SLEEP_TASK', -- https://www.sqlskills.com/help/waits/SLEEP_TASK
N'SLEEP_TEMPDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_TEMPDBSTARTUP
N'SNI_HTTP_ACCEPT', -- https://www.sqlskills.com/help/waits/SNI_HTTP_ACCEPT
N'SOS_WORK_DISPATCHER', -- https://www.sqlskills.com/help/waits/SOS_WORK_DISPATCHER
N'SP_SERVER_DIAGNOSTICS_SLEEP', -- https://www.sqlskills.com/help/waits/SP_SERVER_DIAGNOSTICS_SLEEP
N'SQLTRACE_BUFFER_FLUSH', -- https://www.sqlskills.com/help/waits/SQLTRACE_BUFFER_FLUSH
N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', -- https://www.sqlskills.com/help/waits/SQLTRACE_INCREMENTAL_FLUSH_SLEEP
N'SQLTRACE_WAIT_ENTRIES', -- https://www.sqlskills.com/help/waits/SQLTRACE_WAIT_ENTRIES
N'VDI_CLIENT_OTHER', -- https://www.sqlskills.com/help/waits/VDI_CLIENT_OTHER
N'WAIT_FOR_RESULTS', -- https://www.sqlskills.com/help/waits/WAIT_FOR_RESULTS
N'WAITFOR', -- https://www.sqlskills.com/help/waits/WAITFOR
N'WAITFOR_TASKSHUTDOWN', -- https://www.sqlskills.com/help/waits/WAITFOR_TASKSHUTDOWN
N'WAIT_XTP_RECOVERY', -- https://www.sqlskills.com/help/waits/WAIT_XTP_RECOVERY
N'WAIT_XTP_HOST_WAIT', -- https://www.sqlskills.com/help/waits/WAIT_XTP_HOST_WAIT
N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', -- https://www.sqlskills.com/help/waits/WAIT_XTP_OFFLINE_CKPT_NEW_LOG
N'WAIT_XTP_CKPT_CLOSE', -- https://www.sqlskills.com/help/waits/WAIT_XTP_CKPT_CLOSE
N'XE_DISPATCHER_JOIN', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_JOIN
N'XE_DISPATCHER_WAIT', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_WAIT
N'XE_TIMER_EVENT' -- https://www.sqlskills.com/help/waits/XE_TIMER_EVENT
)
AND [waiting_tasks_count] > 0
)
SELECT
MAX ([W1].[wait_type]) AS [WaitType],
CAST (MAX ([W1].[WaitS]) AS DECIMAL (16,2)) AS [Wait_S],
CAST (MAX ([W1].[ResourceS]) AS DECIMAL (16,2)) AS [Resource_S],
CAST (MAX ([W1].[SignalS]) AS DECIMAL (16,2)) AS [Signal_S],
MAX ([W1].[WaitCount]) AS [WaitCount],
CAST (MAX ([W1].[Percentage]) AS DECIMAL (5,2)) AS [Percentage],
CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgWait_S],
CAST ((MAX ([W1].[ResourceS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgRes_S],
CAST ((MAX ([W1].[SignalS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgSig_S]
FROM [Waits] AS [W1]
INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum]
GROUP BY [W1].[RowNum]
HAVING SUM ([W2].[Percentage]) - MAX( [W1].[Percentage] ) < 95; -- percentage threshold
GO
Để đánh giá được vấn đề bottlenecks, hay để hiểu ý nghĩa của kết quả ở trên, chúng ta đầu tiên cần hiểu được ý nghĩa của một số wait_type
phổ biến thường gặp ở hệ thống OLTP.
Một số Wait_type
thường gặp trong các hệ thống OLTP
LCK_*
Đây chính là lock trên tài nguyên, khi một session cần lấy 1 lock nhưng lock này lại đang được nắm giữ bởi một session khác.
LCK_M_S
: lock để select tài nguyên;LCK_M_X
,LCK_M_IX
,LCK_M_U
: lock để update tài nguyên;LCK_M_SCH_S
: lock tài nguyên để thay đổi schema (ví dụ thường thấy là session đó đang rebuild index)
Để giảm thiểu blocking trên những wait_type
này, thông thường chúng ta thường review lại các query liên quan để giảm thiểu xung đột (xem xét index sử dụng trong các query,…)
Riêng với LCK_M_SCH_S
ta có thể xem lại các task đang thực hiện rebuild, reorganize index trên db đã chạy vào các thời điểm hợp lý chưa. Vì nó là giá trị tích lũy qua các lần rebuild, nên chưa hẳn đã là vấn đề hiệu năng.
HADR_SYNC_COMMIT
Đây là wait_type
khi hệ thống AAG đồng bộ transaction log từ node primary về node secondary (tức là node secondary chạy AAG với mode synchronous_commit
).
Wait type này chưa hẳn là một vấn đề hiệu năng. Nhưng nếu wait_time
tích lũy quá cao, chúng ta cần xem xét đến các vấn đề như:
- Cấu hình trên các node AAG đang không tương đương nhau (secondary cấu hình CPU thấp hơn chẳng hạn);
- Network giữa các node có quá tải hay không;
- 1 node secondary có nhất thiết chạy với
synchronous_commit
không, có thể cấu hìnhasynchronous_commit
nếu 2 node khác DC.
PAGEIOLATCH_*
Wait type này thể hiện việc đọc/ghi dữ liệu (I/O) từ mdf file
và buffer cache
(memory) của SQL Server.
Nếu wait_time
lớn có thể xem xét các nguyên nhân sau:
- Ổ đĩa
read/write
chậm, có thể xem xét dựa vào query bên dưới; - Quá tải ở
tempdb
: Thêm/xóa 1 lượng lớn dữ liệu ởtempdb
; - Thiếu memory dẫn đến việc thường xuyên phải lấy dữ liệu từ disk thay vì ở buffer_cache…
Query kiểm tra tốc độ read/write của disk có đang trễ hay không:
-- The Average Total Latency
-- Excellent <1 ms
--
-- Very good <5 ms
--
-- Good <5 – 10 ms
--
-- Poor < 10 – 20 ms
--
-- Bad < 20 – 100 ms
--
-- Very Bad <100 ms -500 ms
--
-- Awful > 500 ms
--
-- sample_ms - bigint- Number of milliseconds since the computer was started. This column can be used to compare different outputs from this function.
SELECT sample_ms,
CAST(io_stall_read_ms / (1.0 + num_of_reads) AS NUMERIC(10, 1)) AS [Average Read latency ms],
CAST(io_stall_write_ms / (1.0 + num_of_writes) AS NUMERIC(10, 1)) AS [Average Write latency ms],
CAST((io_stall_read_ms + io_stall_write_ms)
/ (1.0 + num_of_reads + num_of_writes)
AS NUMERIC(10, 1)) AS [Average Total Latency ms]
FROM sys.dm_io_virtual_file_stats(DB_ID(), NULL)
WHERE FILE_ID <> 2;
WRITELOG
Đây cũng là 1 wait_type
liên quan đến Disk I/O.
Ghi nhận thời gian chờ khi SQL Server thực hiện ghi dữ liệu từ buffer_cache
xuống transaction_log_file
(ldf).
Có thể xem xét phân bổ lại phân vùng của các file mdf, ldf, tempdb để tránh cao tải trên 1 phân vùng ổ đĩa (xem bài viết)
ASYNC_NETWORK_IO
Tuy có chữ network trong tên nhưng wait này không liên quan gì đến vấn đề network cả.
Thực tế vấn đề nằm ở Client đang xử lý dữ liệu trả về từ truy vấn quá lâu (chưa thể end transaction). Ví dụ, query trả về result_set 10.000 row, Java Spring app xử lý row-by-row để mapping đối tượng (Hibernate chẳng hạn), và chưa thể kết thúc transaction.
Cách xử lý là xem xét lại source code từ client đang thực hiện xử lý result_set trả về từ truy vấn. Ví dụ nhận result_set, thực hiện end transaction trước khi xử lý result_set.
CXPACKET
Bản thân wait này, kể cả wait_time cao hay thấp, không phải là vấn đề hiệu năng.
Nó ghi nhận thời gian khi một worker_thread kết thúc sub_task (trong một quá trình tính toán song song), nhanh hơn các worker_thread khác đang cùng thực hiện sub_task từ task tương ứng.
Giống như 1 nhân viên A giỏi và xử lý vấn đề nhanh hơn các nhân viên khác. A kết thúc công việc trước, và kêu lên với sếp “Mấy thằng kia chậm quá, cho tao task mới đi”; khi đó SQL Server ghi nhận wait_time là thời gian lúc A kêu đến khi có task mới.
Tuy nhiên nếu không có CXPACKET
từ lịch sử, lại là vấn đề, khi đó ta cần xem xét các cấu hình liên quan đến tính toán song song (xem bài viết)
SOS_SCHEDULER_YIELD
Có một trường hợp khi 1 thread đang chạy ở CPU (RUNNING
) tuy nhiên quá 4ms vẫn chưa thể thực hiện, thread này bị đưa quay về trạng thái RUNNABLE
và back về running_queue
.
Và loại wait này ghi nhận thời gian để thread đó có thể rời queue và quay lại trạng thái chạy ở CPU.
Loại wait này cũng thể hiện rằng có thể CPU đang thiếu.
Kết luận
Dựa vào 2 DMV trên, chúng ta có thể có thêm công cụ, kỹ thuật để có thể phát hiện các vấn đề hiệu năng với SQL Server; cũng như phát hiện một số logic ở ứng dụng chưa chính xác.
Từ đó có thể sử dụng thêm các công cụ, query khác để có thêm thông tin về các điểm nghẽn hiệu năng ở Disk I/O, CPU, Network, Memory,…
Việc đo lường thường xuyên (maintain) dựa trên DMV sys.dm_os_waiting_stats
là cần thiết, và dựa trên baseline
của mỗi hệ thống ứng dụng,
để có thể xác định được liệu có các chỉ số nào đang vượt ngưỡng hay không. Chúng ta sẽ đi sâu vào vấn đề này ở các bài viết sau.
Tham khảo
https://www.red-gate.com/products/dba/sql-monitor/resources/articles/monitor-sql-server-io
https://www.sqlskills.com/blogs/paul/wait-statistics-or-please-tell-me-where-it-hurts/
https://www.brentozar.com/archive/2013/08/what-is-the-cxpacket-wait-type-and-how-do-you-reduce-it/