Các câu lệnh SQL Server chậm liên tục trên SQL Server 2008 R2


13

Trên một trong những khách hàng của chúng tôi, chúng tôi đã gặp một số vấn đề về hiệu suất trên ứng dụng của mình. Đây là một ứng dụng web .NET 3.5 đang tiêu thụ và cập nhật dữ liệu trên cơ sở dữ liệu SQL Server. Hiện tại môi trường sản xuất của chúng tôi bao gồm một máy Windows 2008 R2 làm mặt trước và cụm SQL Server 2008 R2 ở mặt sau. Ứng dụng của chúng tôi sử dụng COM + và MSDTC để kết nối với cơ sở dữ liệu.

Đây là những gì đang xảy ra: người dùng cuối của chúng tôi đôi khi phàn nàn về sự chậm chạp trong ứng dụng. Một số trang mất nhiều thời gian hơn để tải hơn dự kiến. Trong khi cố gắng tìm hiểu điều gì đang xảy ra, tôi đã tìm ra một số hành vi lạ ở phía cơ sở dữ liệu có thể là nguyên nhân dẫn đến sự suy giảm hiệu suất. Tôi nhận thấy rằng đôi khi có một số câu lệnh SQL mất nhiều thời gian hơn để chạy những gì sẽ được mong đợi. Tôi đã quản lý để xác định một số trong các tuyên bố này (chủ yếu là các yêu cầu của một số quy trình được lưu trữ trong ứng dụng của chúng tôi) bằng cách sử dụng dấu vết hồ sơ (với mẫu TSQL_Duration) để xác định các truy vấn chạy dài.

Vấn đề là khi tôi chạy các thủ tục được lưu trữ này trực tiếp trên cơ sở dữ liệu trên SQL Management Studio, đôi khi chúng mất nhiều thời gian (khoảng 7/8 giây), những lần khác chúng rất nhanh (dưới 1 giây). Tôi không biết tại sao điều này xảy ra và nó khiến tôi phát điên, vì máy SQL (4 lõi, 32 GB) không được sử dụng bởi bất kỳ ứng dụng nào khác và các truy vấn này sẽ không mất nhiều thời gian để chạy.

Không phải là một DBA hay một chuyên gia máy chủ SQL, tôi đã cố gắng xem xét một số thứ có thể giúp tôi hiểu vấn đề. Đây là các bước tôi đã thực hiện để thử và giải quyết vấn đề và những gì tôi đã tìm ra cho đến nay:

  • Tất cả các mã TSQL được gọi bởi ứng dụng được viết trong các thủ tục được lưu trữ.
  • Tôi đã xác định một số truy vấn chạy dài trên trình hồ sơ SQL Server, tuy nhiên khi tôi chạy những truy vấn này trên Management Studio, chúng sẽ mất nhiều thời gian để chạy (từ 4 đến 10 giây.) Hoặc chạy nhanh (dưới 1 giây). Tôi đang chạy các truy vấn chính xác giống nhau với cùng một dữ liệu được truyền trong các tham số. Các truy vấn này chủ yếu được lưu trữ các thủ tục với các câu lệnh chọn trong đó.
  • Tôi đã thử nhìn vào số liệu thống kê về hàng đợi và hàng đợi để thử và tìm hiểu xem có các quy trình đang chờ trên một số tài nguyên không. Tôi đã chạy truy vấn sau đây:

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 (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',  'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',     'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
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
GO

Đây là những gì tôi phát hiện ra:

  • Sau khi tôi đặt lại các số liệu thống kê bằng DBCC SQLPERF (khoảng 1 hoặc 2 giờ sau), các loại chờ tôi có nhiều nhất là SOS_SCHEDULER_YIELD và WRITELOG
  • Theo thời gian (sau khoảng 1 ngày thực hiện), các loại chờ xảy ra nhiều nhất trên cơ sở dữ liệu là CXPACKET (67%) và OLEDB (17%), mặc dù thời gian chờ trung bình cho mỗi loại không dài. Tôi cũng nhận thấy rằng các câu lệnh chạy dài hơn được xác định trên SQL Profiler là các lệnh gọi đến các thủ tục được lưu trữ trả về nhiều hơn một tập kết quả (thường là 3). Có thể có một vấn đề paralellism ở đây? Có cách nào tôi có thể cố gắng xác định nếu đây là nguyên nhân của vấn đề?
  • Tôi đã đọc ở đâu đó rằng OLEDB chờ đợi có thể được gây ra bởi các cuộc gọi đến tài nguyên OLEDB như các máy chủ được liên kết. Chúng tôi có một máy chủ được liên kết để kết nối với máy Dịch vụ lập chỉ mục (MSIDXS), tuy nhiên không có câu lệnh nào được xác định là chạy lâu sử dụng máy chủ được liên kết đó.
  • Thời gian chờ trung bình cao hơn mà tôi có là dành cho loại chờ LCK_M_X (trung bình khoảng 1,5 giây), nhưng các loại chờ này không xảy ra rất thường xuyên so với các loại khác (ví dụ: 64 LCK_M_X chờ so với 10.823 CXPACKET chờ trong cùng khoảng thời gian ).
  • Một điều tôi nhận thấy là dịch vụ MSDTC không được nhóm. Dịch vụ SQL Server được phân cụm nhưng không phải MSDTC. Có thể có một hit hiệu suất vì điều này? Chúng tôi đang sử dụng MSDTC vì ứng dụng của chúng tôi sử dụng Dịch vụ doanh nghiệp (DCOM) để truy cập cơ sở dữ liệu, nhưng các máy chủ không được chúng tôi cài đặt và định cấu hình, mà bởi khách hàng của chúng tôi.

Bất cứ ai có thể giúp tôi làm cho một số ý nghĩa hơn của dữ liệu này? Bất cứ ai có thể giúp tôi hiểu những gì có thể xảy ra? Có điều gì tôi có thể làm trên máy chủ để thử và tìm hiểu mọi thứ không? Tôi có nên nói chuyện với nhóm phát triển ứng dụng?

Câu trả lời:


4

Cảm ơn bạn đã giải thích chi tiết về vấn đề của bạn (một trong những câu hỏi được đặt ra tốt nhất thực sự).

WRITELOG là một loại chờ đợi rất phổ biến, vì vậy đừng lo lắng về nó. Nhìn vào SOS_SCHEDULER_YIELD chỉ ra áp suất CPU và cả CXPACKET, có thể phải có một số chỉ mục bị thiếu và bạn có thể đang truy xuất nhiều dữ liệu từ các truy vấn cho hệ thống OLTP. Tôi đề nghị bạn nên xem DMV Indexing mất tích và xem liệu có bất kỳ chỉ mục nào (gần như chắc chắn sẽ có nhiều hơn) trong các procs nghi vấn.

http://sqlfool.com/2009/04/a-look-at-missing-indexes/

http://troubledhootingsql.com/2009/12/30/how-to-find-out-the-missing-indexes-on-a-sql-server-2008-or-2005-instance-along-with-the- tạo chỉ mục lệnh /

Hãy tìm bài viết của Jonathan Kehayias trên sqlblog.com về điều này.

Ngoài ra, hãy xem Thông số đánh hơi.

http://sommarskog.se/query-plan-mysteries.html

http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

Đây KHÔNG phải là câu trả lời cạnh tranh cho nhu cầu của bạn mà là điểm khởi đầu tốt. Hãy cho chúng tôi biết nếu bạn cần thêm chi tiết.


1

Chúng tôi đã có một vấn đề tương tự sau khi một trong các nhân viên viết lại một vài thủ tục được lưu trữ. Hóa ra có sự phân nhánh quá mức và SQL động được xây dựng đã thay đổi mệnh đề where đáng kể.

Ví dụ (đơn giản hóa tất nhiên):

Nếu là người mẫu là "X" thì mệnh đề where tìm ProductCode bằng các giá trị nhất định.
Nếu Model là "Y" thì mệnh đề where tìm ProductType bằng các giá trị nhất định.

SQL Server sẽ xây dựng một kế hoạch truy vấn dựa trên các tham số đầu vào trong lần đầu tiên thủ tục được lưu trữ được thực thi. Vì vậy, nếu kế hoạch truy vấn được xây dựng dựa trên logic sử dụng "ProductCode" bằng và bạn đang yêu cầu "ProductType" bằng với kế hoạch truy vấn không khớp và rất có thể dẫn đến quét toàn bộ bảng.

Bạn có thể thử đặt " VỚI RECOMPILE " ở đầu quy trình được lưu trữ. THỦ TỤC TẠO (Transact-SQL)

Cách tốt nhất tôi có thể mô tả điều này là như sau:

Giả sử bạn có một danh sách tên và số điện thoại được sắp xếp theo Họ. Điều này hoạt động rất tốt để tìm người sử dụng Họ của họ (kế hoạch truy vấn dựa trên Họ). Bây giờ, giả sử bạn cần tất cả tên và số điện thoại trong Mã vùng 203. Nếu danh sách của bạn được sắp xếp theo Họ, cách duy nhất để có được danh sách đầy đủ của tất cả mọi người Mã vùng 203 là bắt đầu từ đầu và đọc tuần tự qua từng và mọi kỷ lục. (Quét toàn bộ bảng).


Sử dụng exec()chức năng sẽ giải thích các hành vi quan sát. Trong trường hợp này, việc sử dụng sp_executesqlthường giải quyết các vấn đề với các câu lệnh SQL động.
ajeh

1

Nếu các truy vấn đang chạy liên tục nhanh và chậm trong SSMS và ứng dụng, bạn có thể có vấn đề đánh hơi thông số hoặc thống kê.

Tôi sẽ thực hiện các thủ tục được lưu trữ này, sau đó xem lại kế hoạch thực hiện để kéo các thuộc tính của toán tử gốc (nút màu xanh lá cây ở phía xa bên trái của mỗi câu lệnh).

Số lượng hàng ước tính trong kế hoạch thực hiện là bao nhiêu, so với số lượng hàng thực tế được trả về là bao nhiêu?

Tham số biên dịch có khớp với tham số truy vấn thực tế không?

Nếu kế hoạch thực hiện được tạo cho một tham số chỉ trả về một số hàng và bạn chạy cùng một quy trình với tham số trả về số lượng lớn hàng, SQL có thể sử dụng kế hoạch thực hiện không chính xác cho truy vấn.

Các lựa chọn kế hoạch thực hiện được liên kết chặt chẽ với các số liệu thống kê SQL, do đó, nên xây dựng lại các số liệu thống kê của bạn một cách thường xuyên.

Nếu bạn có một quy trình được lưu trữ đôi khi trả về một lượng nhỏ dữ liệu hoặc một lượng lớn dữ liệu tùy thuộc vào tham số được cung cấp, bạn có thể gặp vấn đề đánh hơi tham số.

Nếu việc xây dựng lại số liệu thống kê của bạn không giải quyết được vấn đề, bạn có thể chạy (các) câu lệnh đắt nhất trong quy trình được lưu trữ với OPTION (RECOMPILE)


0

Khi bạn đã xác định các truy vấn chạy dài, bạn có thể tìm nạp các kế hoạch thực hiện cho các quy trình này từ bộ đệm của mình và xem liệu bạn có thể xác định sự cố ở đó không. Thường có các chuyển đổi ngầm định hoặc thời gian chạy của các loại dữ liệu. Ngoài ra, nếu bạn lọc hoặc chèn nhiều dữ liệu, bạn cũng nên cập nhật số liệu thống kê.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.