Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

SQL Server 2016:sys.dm_exec_osystem_stats

Trong SQL Server 2016 CTP 2.1, có một đối tượng mới xuất hiện sau CTP 2.0:sys.dm_exec_osystem_stats. Điều này nhằm cung cấp chức năng tương tự cho sys.dm_exec_procedure_stats, sys.dm_exec_query_stats và sys.dm_exec_trigger_stats. Vì vậy, giờ đây có thể theo dõi chỉ số thời gian chạy tổng hợp cho các chức năng do người dùng xác định.

Hay là nó?

Ít nhất trong CTP 2.1, tôi chỉ có thể lấy được bất kỳ số liệu có ý nghĩa nào ở đây cho các hàm vô hướng thông thường - không có gì được đăng ký cho TVF nội tuyến hoặc nhiều câu lệnh. Tôi không ngạc nhiên về các hàm nội tuyến, vì dù sao thì chúng cũng được mở rộng trước khi thực thi. Nhưng vì các TVF nhiều tuyên bố thường là những vấn đề về hiệu suất, tôi đã hy vọng chúng cũng sẽ xuất hiện. Chúng vẫn xuất hiện trong sys.dm_exec_query_stats, vì vậy bạn vẫn có thể lấy số liệu hiệu suất của chúng từ đó, nhưng có thể khó thực hiện tổng hợp khi bạn thực sự có nhiều câu lệnh thực hiện một số phần của công việc - không có gì được tổng hợp cho bạn.

Chúng ta hãy xem nhanh cách điều này diễn ra. Giả sử chúng ta có một bảng đơn giản với 100.000 hàng:

SELECT TOP (100000) o1.[object_id], o1.create_date
  INTO dbo.src
  FROM sys.all_objects AS o1
  CROSS JOIN sys.all_objects AS o2
  ORDER BY o1.[object_id];
GO
CREATE CLUSTERED INDEX x ON dbo.src([object_id]);
GO
-- prime the cache
SELECT [object_id], create_date FROM dbo.src;

Tôi muốn so sánh điều gì sẽ xảy ra khi chúng tôi điều tra các UDF vô hướng, các hàm có giá trị bảng đa câu lệnh và các hàm có giá trị bảng nội tuyến và cách chúng tôi xem công việc đã được thực hiện trong từng trường hợp như thế nào. Đầu tiên, hãy tưởng tượng một điều gì đó nhỏ nhặt mà chúng ta có thể làm trong SELECT , nhưng chúng tôi có thể muốn chia nhỏ kích thước, chẳng hạn như định dạng ngày dưới dạng chuỗi:

CREATE PROCEDURE dbo.p_dt_Standard
  @dt_ CHAR(10) = NULL
AS
BEGIN
  SET NOCOUNT ON;
  SELECT @dt_ = CONVERT(CHAR(10), create_date, 120)
    FROM dbo.src
    ORDER BY [object_id];
END
GO

(Tôi gán kết quả đầu ra cho một biến, điều này buộc toàn bộ bảng phải được quét, nhưng ngăn các chỉ số hiệu suất không bị ảnh hưởng bởi nỗ lực của SSMS trong việc sử dụng và hiển thị kết quả. Cảm ơn lời nhắc, Mikael Eriksson.)

Rất nhiều lần bạn sẽ thấy mọi người đặt chuyển đổi đó vào một hàm và nó có thể là vô hướng hoặc TVF, như sau:

CREATE FUNCTION dbo.dt_Inline(@dt_ DATETIME)
RETURNS TABLE
AS
  RETURN (SELECT dt_ = CONVERT(CHAR(10), @dt_, 120));
GO
 
CREATE FUNCTION dbo.dt_Multi(@dt_ DATETIME)
RETURNS @t TABLE(dt_ CHAR(10))
AS
BEGIN
  INSERT @t(dt_) SELECT CONVERT(CHAR(10), @dt_, 120);
  RETURN;
END
GO
 
CREATE FUNCTION dbo.dt_Scalar(@dt_ DATETIME)
RETURNS CHAR(10)
AS
BEGIN
  RETURN (SELECT CONVERT(CHAR(10), @dt_, 120));
END
GO

Tôi đã tạo các trình bao bọc thủ tục xung quanh các hàm này như sau:

CREATE PROCEDURE dbo.p_dt_Inline
  @dt_ CHAR(10) = NULL
AS
BEGIN
  SET NOCOUNT ON;
  SELECT @dt_ = dt.dt_
    FROM dbo.src AS o
    CROSS APPLY dbo.dt_Inline(o.create_date) AS dt
    ORDER BY o.[object_id];
END
GO
 
CREATE PROCEDURE dbo.p_dt_Multi
  @dt_ CHAR(10) = NULL
AS
BEGIN
  SET NOCOUNT ON;
  SELECT @dt_ = dt.dt_
    FROM dbo.src
    CROSS APPLY dbo.dt_Multi(create_date) AS dt
    ORDER BY [object_id];
END
GO
 
CREATE PROCEDURE dbo.p_dt_Scalar
  @dt_ CHAR(10) = NULL
AS
BEGIN
  SET NOCOUNT ON;
  SELECT @dt_ = dt = dbo.dt_Scalar(create_date)
    FROM dbo.src
    ORDER BY [object_id];
END
GO

(Và không, dt_ quy ước bạn đang thấy không phải là một số điều mới mẻ, tôi nghĩ đó là một ý tưởng hay, đó chỉ là cách đơn giản nhất tôi có thể tách tất cả các truy vấn này trong DMV khỏi mọi thứ khác đang được thu thập. Nó cũng giúp dễ dàng thêm các hậu tố để dễ dàng phân biệt giữa truy vấn bên trong thủ tục được lưu trữ và phiên bản đặc biệt.)

Tiếp theo, tôi tạo bảng #temp để lưu trữ thời gian và lặp lại quá trình này (vừa thực hiện thủ tục được lưu trữ hai lần, vừa thực thi phần thân của thủ tục dưới dạng truy vấn đặc biệt riêng biệt hai lần và theo dõi thời gian của mỗi lần):

CREATE TABLE #t
(
  ID INT IDENTITY(1,1), 
  q VARCHAR(32), 
  s DATETIME2, 
  e DATETIME2
);
GO
 
INSERT #t(q,s) VALUES('p Standard',SYSDATETIME());
GO
 
EXEC dbo.p_dt_Standard;
GO 2
 
UPDATE #t SET e = SYSDATETIME() WHERE ID = 1;
GO
 
INSERT #t(q,s) VALUES('ad hoc Standard',SYSDATETIME());
GO
 
DECLARE @dt_st CHAR(10);
  SELECT @dt_st = CONVERT(CHAR(10), create_date, 120)
    FROM dbo.src
    ORDER BY [object_id];
GO 2
 
UPDATE #t SET e = SYSDATETIME() WHERE ID = 2;
GO
-- repeat for inline, multi and scalar versions

Sau đó, tôi chạy một số truy vấn chẩn đoán và đây là kết quả:

sys.dm_exec_ Chức năng_stats

SELECT name = OBJECT_NAME(object_id), 
  execution_count,
  time_milliseconds = total_elapsed_time/1000
FROM sys.dm_exec_function_stats
WHERE database_id = DB_ID()
ORDER BY name;

Kết quả:

name        execution_count    time_milliseconds
---------   ---------------    -----------------
dt_Scalar   400000             1116

Đó không phải là một lỗi đánh máy; chỉ UDF vô hướng mới hiển thị bất kỳ sự hiện diện nào trong DMV mới.

sys.dm_exec_procedure_stats

SELECT name = OBJECT_NAME(object_id), 
  execution_count,
  time_milliseconds = total_elapsed_time/1000
FROM sys.dm_exec_procedure_stats
WHERE database_id = DB_ID()
ORDER BY name;

Kết quả:

name            execution_count    time_milliseconds
-------------   ---------------    -----------------
p_dt_Inline     2                  74
p_dt_Multi      2                  269
p_dt_Scalar     2                  1063
p_dt_Standard   2                  75

Đây không phải là một kết quả đáng ngạc nhiên:sử dụng hàm vô hướng dẫn đến hình phạt hiệu suất theo thứ tự độ lớn, trong khi TVF đa câu lệnh chỉ kém hơn khoảng 4 lần. Qua nhiều lần kiểm tra, chức năng nội tuyến luôn nhanh hơn hoặc nhanh hơn một phần nghìn giây so với không có chức năng nào.

sys.dm_exec_query_stats

SELECT 
  query = SUBSTRING([text],s,e), 
  execution_count, 
  time_milliseconds
FROM
(
  SELECT t.[text],
    s = s.statement_start_offset/2 + 1,
    e = COALESCE(NULLIF(s.statement_end_offset,-1),8000)/2,
    s.execution_count,
    time_milliseconds = s.total_elapsed_time/1000
  FROM sys.dm_exec_query_stats AS s
  OUTER APPLY sys.dm_exec_sql_text(s.[sql_handle]) AS t
  WHERE t.[text] LIKE N'%dt[_]%' 
) AS x;

Kết quả bị cắt bớt, được sắp xếp lại theo cách thủ công:

query (truncated)                                                       execution_count    time_milliseconds
--------------------------------------------------------------------    ---------------    -----------------
-- p Standard:
SELECT @dt_ = CONVERT(CHAR(10), create_date, 120) ...                   2                  75
-- ad hoc Standard:
SELECT @dt_st = CONVERT(CHAR(10), create_date, 120) ...                 2                  72
 
-- p Inline:
SELECT @dt_ = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Inline...     2                  74
-- ad hoc Inline:
SELECT @dt_in = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Inline...   2                  72
 
-- all Multi:
INSERT @t(dt_) SELECT CONVERT(CHAR(10), @dt_, 120);                     184                5
-- p Multi:
SELECT @dt_ = dt.dt_ FROM dbo.src CROSS APPLY dbo.dt_Multi...           2                  270
-- ad hoc Multi:
SELECT @dt_m = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Multi...     2                  257
 
-- all scalar:
RETURN (SELECT CONVERT(CHAR(10), @dt_, 120));                           400000             581
-- p Scalar:
SELECT @dt_ = dbo.dt_Scalar(create_date)...                             2                  986
-- ad hoc Scalar:
SELECT @dt_sc = dbo.dt_Scalar(create_date)...                           2                  902

Một điều quan trọng cần lưu ý ở đây là thời gian tính bằng mili giây cho câu lệnh INSERT trong TVF đa câu lệnh và câu lệnh RETURN trong hàm vô hướng cũng được tính trong các câu lệnh SELECT riêng lẻ, vì vậy không có ý nghĩa gì nếu chỉ cộng tất cả thời gian.

Định giờ thủ công

Và cuối cùng là thời gian từ bảng #temp:

SELECT query = q, 
    time_milliseconds = DATEDIFF(millisecond, s, e) 
  FROM #t 
  ORDER BY ID;

Kết quả:

query             time_milliseconds
---------------   -----------------
p Standard        107
ad hoc Standard   78
p Inline          80
ad hoc Inline     78
p Multi           351
ad hoc Multi      263
p Scalar          992
ad hoc Scalar     907

Kết quả thú vị bổ sung ở đây:trình bao bọc thủ tục luôn có một số chi phí, mặc dù mức độ quan trọng của điều đó có thể thực sự chủ quan.

Tóm tắt

Quan điểm của tôi ở đây hôm nay chỉ là để hiển thị DMV mới đang hoạt động và đặt kỳ vọng một cách chính xác - một số chỉ số hiệu suất cho các chức năng sẽ vẫn gây hiểu nhầm và một số sẽ vẫn không có sẵn (hoặc ít nhất là rất tẻ nhạt để tự ghép lại với nhau cho chính bạn ).

Tôi nghĩ rằng DMV mới này bao gồm một trong những phần quan trọng nhất của việc giám sát truy vấn mà SQL Server đã thiếu trước đây:rằng các hàm vô hướng đôi khi là những kẻ giết hiệu suất vô hình, bởi vì cách đáng tin cậy duy nhất để xác định việc sử dụng chúng là phân tích cú pháp văn bản truy vấn. còn lâu mới an toàn. Đừng bận tâm đến thực tế là điều đó sẽ không cho phép bạn tách biệt tác động của chúng đối với hiệu suất hoặc bạn phải biết là đang tìm kiếm các UDF vô hướng trong văn bản truy vấn ngay từ đầu.

Phụ lục

Tôi đã đính kèm tập lệnh:DMExecFunctionStats.zip

Ngoài ra, kể từ CTP1, đây là tập hợp các cột:

database_id object_id type type_desc
sql_handle plan_handle cached_time last_execution_time execution_count
total_worker_time last_worker_time min_worker_time max_worker_time
total_physical_reads last_physical_reads min_physical_reads max_physical_reads
total_logical_writes last_logical_writes min_logical_writes max_logical_writes
total_logical_reads last_logical_reads min_logical_reads max_logical_reads
total_elapsed_time last_elapsed_time min_elapsed_time max_elapsed_time

Các cột hiện ở sys.dm_exec_osystem_stats


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Thay đổi Dấu phân cách thành Dấu phẩy khi gửi kết quả truy vấn qua email trong SQL Server (T-SQL)

  2. SQL Server:Rò rỉ mức cách ly trên các kết nối được gộp chung

  3. Có thể sử dụng `SqlDbType.Structured` để chuyển các Tham số Giá trị Bảng trong NHibernate không?

  4. Cách duy trì thứ tự chèn trong SQL Server

  5. 4 lý do tại sao bạn nên ưu tiên giám sát cơ sở dữ liệu trong kế hoạch năm 2020 của mình