Hiệu suất của SQL Server: PREEMPTIVE_OS_DELETESECURITYCONTEXT loại chờ đợi chiếm ưu thế


8

Tôi đã nhận được một cuộc gọi ngày hôm qua từ một khách hàng đang phàn nàn về việc sử dụng CPU cao trên SQL Server của họ. Chúng tôi đang sử dụng SQL Server 2012 64 bit SE. Máy chủ đang chạy Windows Server 2008 R2 Standard, Intel Xeon 2.20 GHz (4 lõi), RAM 16 GB.

Sau khi chắc chắn rằng thủ phạm thực sự là SQL Server, tôi đã xem xét các trường hợp chờ đợi hàng đầu bằng cách sử dụng truy vấn DMV ở đây . Hai chờ đợi hàng đầu là: (1) PREEMPTIVE_OS_DELETESECURITYCONTEXTvà (2) SOS_SCHEDULER_YIELD.

EDIT : Đây là kết quả của "truy vấn chờ đợi hàng đầu" (mặc dù ai đó đã khởi động lại máy chủ sáng nay theo mong muốn của tôi):

nhập mô tả hình ảnh ở đây

Chúng tôi thực hiện rất nhiều tính toán / chuyển đổi mạnh mẽ, vì vậy tôi có thể hiểu SOS_SCHEDULER_YIELD. Tuy nhiên, tôi rất tò mò về PREEMPTIVE_OS_DELETESECURITYCONTEXTloại chờ đợi và tại sao nó có thể là cao nhất.

Mô tả / thảo luận tốt nhất mà tôi có thể tìm thấy về loại chờ này có thể được tìm thấy ở đây . Nó đề cập đến:

Các loại chờ PREEMPTIVE_OS_ là các cuộc gọi rời khỏi cơ sở dữ liệu, thường là API Win32 và đang thực hiện mã bên ngoài SQL Server cho các tác vụ khác nhau. Trong trường hợp này, nó đang xóa một bối cảnh bảo mật được sử dụng trước đây để truy cập tài nguyên từ xa. API liên quan thực sự có tên là DeleteSecurityContext ()

Theo hiểu biết của tôi, chúng tôi không có bất kỳ tài nguyên bên ngoài nào như máy chủ được liên kết hoặc tập tin. Và chúng tôi không thực hiện bất kỳ hành vi mạo danh nào, v.v. Có thể một bản sao lưu đã khiến điều này tăng đột biến hoặc có thể là bộ điều khiển miền bị lỗi?

Cái quái gì có thể khiến điều này trở thành kiểu chờ đợi thống trị? Làm thế nào tôi có thể theo dõi loại chờ này hơn nữa?

Chỉnh sửa 2: Tôi đã kiểm tra nội dung của Nhật ký bảo mật Windows. Tôi thấy một vài mục có thể được quan tâm, nhưng tôi không chắc liệu đây có phải là bình thường không:

Special privileges assigned to new logon.

Subject:
    Security ID:        NT SERVICE\MSSQLServerOLAPService
    Account Name:       MSSQLServerOLAPService
    Account Domain:     NT Service
    Logon ID:       0x3143c

Privileges:     SeImpersonatePrivilege

Special privileges assigned to new logon.

Subject:
    Security ID:        NT SERVICE\MSSQLSERVER
    Account Name:       MSSQLSERVER
    Account Domain:     NT Service
    Logon ID:       0x2f872

Privileges:     SeAssignPrimaryTokenPrivilege
            SeImpersonatePrivilege

Chỉnh sửa 3 : @Jon Seigel, như bạn yêu cầu, đây là kết quả của truy vấn của bạn. Một chút khác biệt so với Paul:

nhập mô tả hình ảnh ở đây

Chỉnh sửa 4: Tôi thừa nhận, tôi là người dùng Sự kiện mở rộng lần đầu tiên. Tôi đã thêm loại chờ này vào sự kiện Wait_info_external và thấy hàng trăm mục nhập. Không có văn bản sql hoặc xử lý kế hoạch, chỉ có một ngăn xếp cuộc gọi. Làm thế nào tôi có thể theo dõi thêm nguồn?

nhập mô tả hình ảnh ở đây


John, Bạn có thể vui lòng chạy sp_whoisactive trong một khoảng thời gian (có thể là một phút) và xem những gì bật lên? Điều này có thể giúp hướng bạn / chúng tôi đến một giải pháp. sqlblog.com/files/default.aspx
Mark Wilkinson

Xin chào John, trong câu hỏi của bạn, bạn đề cập đến việc xác định SQL Server là thủ phạm. Bạn có thể vui lòng mô tả các bước bạn đã thực hiện để đi đến kết luận đó?
Craig Efrein

Câu trả lời:


3

Tôi biết câu hỏi này, dựa trên Tiêu đề, chủ yếu liên quan đến loại chờ PREEMPTIVE_OS_DELETESECURITYCONTEXT, nhưng tôi tin rằng đó là một sự đánh giá sai về vấn đề thực sự là " một khách hàng phàn nàn về việc sử dụng CPU cao trên SQL Server của họ ".

Lý do tôi tin rằng việc tập trung vào loại chờ đợi cụ thể này là một cuộc rượt đuổi ngông cuồng là bởi vì nó đi lên cho mọi kết nối được thực hiện. Tôi đang chạy truy vấn sau trên máy tính xách tay của mình (nghĩa là tôi là người dùng duy nhất):

SELECT * 
FROM sys.dm_os_wait_stats
WHERE wait_type = N'PREEMPTIVE_OS_DELETESECURITYCONTEXT'

Và sau đó tôi thực hiện bất kỳ thao tác nào sau đây và chạy lại truy vấn này:

  • mở một tab truy vấn mới
  • đóng tab truy vấn mới
  • chạy phần sau từ dấu nhắc DOS: SQLCMD -E -Q "select 1"

Bây giờ, chúng ta biết rằng CPU cao, vì vậy chúng ta nên xem những gì đang chạy để xem phiên nào có CPU cao:

SELECT req.session_id AS [SPID],
       req.blocking_session_id AS [BlockedBy],
       req.logical_reads AS [LogReads],
       DB_NAME(req.database_id) AS [DatabaseName],
       SUBSTRING(txt.[text],
                 (req.statement_start_offset / 2) + 1,
                 CASE
                     WHEN req.statement_end_offset > 0
                        THEN (req.statement_end_offset - req.statement_start_offset) / 2
                     ELSE LEN(txt.[text])
                 END
                ) AS [CurrentStatement],
       txt.[text] AS [CurrentBatch],
       CONVERT(XML, qplan.query_plan) AS [StatementQueryPlan],
       OBJECT_NAME(qplan.objectid, qplan.[dbid]) AS [ObjectName],
       sess.[program_name],
       sess.[host_name],
       sess.nt_user_name,
       sess.total_scheduled_time,
       sess.memory_usage,
       req.*
FROM sys.dm_exec_requests req
INNER JOIN sys.dm_exec_sessions sess
        ON sess.session_id = req.session_id
CROSS APPLY sys.dm_exec_sql_text(req.[sql_handle]) txt
OUTER APPLY sys.dm_exec_text_query_plan(req.plan_handle,
                                        req.statement_start_offset,
                                        req.statement_end_offset) qplan
WHERE req.session_id <> @@SPID
ORDER BY req.logical_reads DESC, req.cpu_time DESC
--ORDER BY req.cpu_time DESC, req.logical_reads DESC

Tôi thường chạy truy vấn trên như vậy, nhưng bạn cũng có thể chuyển đổi mệnh đề ORDER BY được nhận xét để xem liệu điều đó có mang lại kết quả thú vị / hữu ích hơn không.

Ngoài ra, bạn có thể chạy các mục sau, dựa trên dm_exec_query_stats, để tìm các truy vấn có chi phí cao nhất. Truy vấn đầu tiên bên dưới sẽ hiển thị cho bạn các truy vấn riêng lẻ (ngay cả khi chúng có nhiều gói) và được sắp xếp theo Thời gian CPU trung bình, nhưng bạn có thể dễ dàng thay đổi đó thành Đọc hợp lý trung bình. Khi bạn tìm thấy một truy vấn có vẻ như đang chiếm nhiều tài nguyên, hãy sao chép "sql_handle" và "statement_start_offset" vào điều kiện WHERE của truy vấn thứ hai bên dưới để xem các gói riêng lẻ (có thể nhiều hơn 1). Cuộn sang bên phải và giả sử đã có Kế hoạch XML, nó sẽ hiển thị dưới dạng một liên kết (ở Chế độ lưới) sẽ đưa bạn đến trình xem kế hoạch nếu bạn nhấp vào nó.

Truy vấn # 1: Nhận thông tin truy vấn

;WITH cte AS
(
   SELECT qstat.[sql_handle],
          qstat.statement_start_offset,
          qstat.statement_end_offset,
          COUNT(*) AS [NumberOfPlans],
          SUM(qstat.execution_count) AS [TotalExecutions],

          SUM(qstat.total_worker_time) AS [TotalCPU],
          (SUM(qstat.total_worker_time * 1.0) / SUM(qstat.execution_count)) AS [AvgCPUtime],
          MAX(qstat.max_worker_time) AS [MaxCPU],

          SUM(qstat.total_logical_reads) AS [TotalLogicalReads],
   (SUM(qstat.total_logical_reads * 1.0) / SUM(qstat.execution_count)) AS [AvgLogicalReads],
          MAX(qstat.max_logical_reads) AS [MaxLogicalReads],

          SUM(qstat.total_rows) AS [TotalRows],
          (SUM(qstat.total_rows * 1.0) / SUM(qstat.execution_count)) AS [AvgRows],
          MAX(qstat.max_rows) AS [MaxRows]
   FROM sys.dm_exec_query_stats  qstat
   GROUP BY qstat.[sql_handle], qstat.statement_start_offset, qstat.statement_end_offset
)
SELECT  cte.*,
        DB_NAME(txt.[dbid]) AS [DatabaseName],
        SUBSTRING(txt.[text],
                  (cte.statement_start_offset / 2) + 1,
                  CASE
                      WHEN cte.statement_end_offset > 0
                          THEN (cte.statement_end_offset - cte.statement_start_offset) / 2
                      ELSE LEN(txt.[text])
                  END
                 ) AS [CurrentStatement],
        txt.[text] AS [CurrentBatch]
FROM cte
CROSS APPLY sys.dm_exec_sql_text(cte.[sql_handle]) txt
ORDER BY cte.AvgCPUtime DESC

Truy vấn # 2: Nhận thông tin kế hoạch

SELECT  *,
        DB_NAME(qplan.[dbid]) AS [DatabaseName],
        CONVERT(XML, qplan.query_plan) AS [StatementQueryPlan],
        SUBSTRING(txt.[text],
                  (qstat.statement_start_offset / 2) + 1,
                  CASE
                        WHEN qstat.statement_end_offset > 0
                        THEN (qstat.statement_end_offset - qstat.statement_start_offset) / 2
                        ELSE LEN(txt.[text])
                  END
                 ) AS [CurrentStatement],
        txt.[text] AS [CurrentBatch]
FROM sys.dm_exec_query_stats  qstat
CROSS APPLY sys.dm_exec_sql_text(qstat.[sql_handle]) txt
OUTER APPLY sys.dm_exec_text_query_plan(qstat.plan_handle,
                                        qstat.statement_start_offset,
                                        qstat.statement_end_offset) qplan
-- paste info from Query #1 below
WHERE qstat.[sql_handle] = 0x020000001C70C614D261C85875D4EF3C90BD18D02D62453800....
AND qstat.statement_start_offset = 164
-- paste info from Query #1 above
ORDER BY qstat.total_worker_time DESC

Tôi nghĩ rằng loại chờ được xếp hạng cao nhất từ ​​tập lệnh của Paul, cụ thể là PREEMPTIVE_OS_DELETESECURITYCONTEXT, có thể là nguyên nhân của CPU cao. Điều này có thể được coi là một loại chờ đợi lành tính trong trường hợp của chúng tôi? Trong ứng dụng của chúng tôi, chúng tôi có một vài dịch vụ windows liên tục gửi lệnh (exec procs lưu trữ) đến SQL Server. Tôi không thể nhận ra quá nhiều mẫu từ sys.dm_exec_sments - các phiên không mở quá lâu và có rất nhiều mẫu. sys.dm_exec_query_stats cung cấp một số thông tin tốt về các procs được lưu trữ đắt nhất cho đến khi tổng chi phí CPU. Đây có thể là một nơi tốt để bắt đầu.
John Russell

Tôi chỉ muốn đảm bảo rằng tôi đã không thiếu thứ gì đó với PREEMPTIVE_OS_DELETESECURITYCONTEXT. Tôi không biết liệu điều này có thể được truy tìm đến bộ điều khiển miền bị lỗi hoặc tra cứu AD không?
John Russell

@ John Johnuss xp_dirtree), do đó âm lượng cao không phải là một chỉ báo thực sự. Và ngay cả khi có độ trễ mạng gây ra sự chậm trễ, điều đó có thực sự làm tăng CPU hay chỉ tăng khả năng chặn? Và điểm tốt, sử dụng query_stats. Tôi sẽ cập nhật truy vấn của tôi sau đó với điều đó.
Solomon Rutzky 17/03/2016

1
@JohnRussell: liên quan đến "các dịch vụ windows liên tục gửi lệnh" của bạn, có gì thay đổi gần đây không? Họ có đóng đúng kết nối không? Họ có làm sạch kết nối đúng cách nếu họ lỗi trong khi kết nối? Ngoài ra, bạn đã xây dựng lại các chỉ mục gần đây hoặc ít nhất là các số liệu thống kê được cập nhật trên tất cả các bảng chưa? Không làm những điều đó có thể dẫn đến tăng CPU.
Solomon Rutzky 17/03/2016

Cảm ơn vì sự sáng suốt! Khi tôi nhìn kỹ hơn vào sys.dm_exec_query_stats và phân mảnh chỉ mục trên một vài bảng chính, tôi bắt đầu cảm thấy tự tin hơn về nguyên nhân. PREEMPTIVE_OS_DELETESECURITYCONTEXT chỉ cần ném tôi đi.
John Russell

1

SecurityContext được sử dụng bởi máy chủ sql ở một số nơi. Một ví dụ mà bạn đã đặt tên là các máy chủ và tệp có thể liên kết. Có lẽ bạn đang sử dụng cmdexec? SQL Server Agent công việc với tài khoản proxy? Gọi một dịch vụ web? Tài nguyên từ xa có thể là rất nhiều điều buồn cười.

Sự kiện mạo danh có thể được đăng nhập trong sự kiện bảo mật windows. Nó có thể là bạn đang tìm thấy một đầu mối ở đó. Hơn nữa, bạn có thể muốn kiểm tra máy ghi hộp đen hay còn gọi là các sự kiện mở rộng.

Bạn đã kiểm tra xem các Loại Chờ này có mới không (và có liên quan đến cpu cao) hay chỉ bình thường đối với máy chủ của bạn?


Chúng tôi không có bất kỳ công việc Đại lý máy chủ SQL cũng như Dịch vụ web. Tôi đã xóa các số liệu thống kê chờ và chạy lại truy vấn ban đầu ở trên và các số liệu thống kê tương tự xuất hiện lại. Tôi đã mất một chút để tìm ra cách cấu hình lại phiên sự kiện mở rộng system_health để bao gồm Wait_info_external cho Waittype = 'PREEMPTIVE_OS_DELETESECURITYCONTEXT', nhưng cuối cùng tôi đã thấy nó được thêm vào, tôi có thể thấy hàng trăm sự kiện này trong vài giây . Tôi đang xem làm thế nào để giải mã tốt hơn nguồn. Bất kỳ lời khuyên về cách theo dõi này xuống?
John Russell
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.