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

Xác định các vấn đề đặt hàng trong sự kiện mở rộng

Trong mọi bài thuyết trình về Sự kiện mở rộng, tôi cố gắng giải thích một trong những điểm khác biệt lớn nhất giữa lọc trong Sự kiện mở rộng và lọc trong Theo dõi; thực tế là thứ tự vị từ quan trọng trong Sự kiện mở rộng. Hầu hết thời gian tôi đang nói về việc đánh giá vị từ trong Sự kiện mở rộng và cố gắng làm cho vị từ sự kiện không thành công trong đánh giá logic càng nhanh càng tốt để trả lại quyền kiểm soát cho tác vụ đang thực thi. Gần đây, tôi đang làm việc với một trong những phiên sự kiện mẫu mà tôi sử dụng trong các bản trình bày thể hiện khía cạnh quan trọng khác của thứ tự vị từ trong Sự kiện mở rộng.

Trong Sự kiện mở rộng có các trình so sánh vị từ dạng văn bản cho phép đưa ra các định nghĩa phức tạp hơn về tiêu chí lọc cho một sự kiện. Một vài trong số này thực sự duy trì trạng thái nội bộ trong khi phiên sự kiện được bắt đầu trên máy chủ, ví dụ:bộ so sánh package0.greater_than_max_uint64 và package0.less_than_min_uint64. Ngoài ra còn có một phần tử nguồn vị ngữ, package0.counter, cũng duy trì trạng thái bên trong khi phiên sự kiện được bắt đầu. Đối với các vị từ duy trì trạng thái trong Sự kiện mở rộng, một trong những cân nhắc quan trọng nhất là trạng thái bên trong thay đổi bất cứ khi nào vị từ duy trì trạng thái được đánh giá, chứ không phải khi sự kiện kích hoạt hoàn toàn. Để chứng minh điều này, chúng ta hãy xem một ví dụ sử dụng trình so sánh vị từ dạng văn bản package0.greater_than_max_uint64. Trước tiên, chúng ta sẽ cần tạo một thủ tục được lưu trữ mà chúng ta có thể kiểm soát thời lượng thực thi của:

USE AdventureWorks2012
GO
IF OBJECT_ID(N'StoredProcedureExceedsDuration') IS NOT NULL
       DROP PROCEDURE dbo.StoredProcedureExceedsDuration;
GO
CREATE PROCEDURE dbo.StoredProcedureExceedsDuration
( @WaitForValue varchar(12) = '00:00:00:050')
AS
       WAITFOR DELAY @WaitForValue;      
GO

Sau đó, chúng ta sẽ cần tạo một phiên sự kiện để theo dõi các thực thi của thủ tục được lưu trữ bằng cách sử dụng sự kiện sqlserver.module_end và lọc các thực thi trên cột object_id và source_database_id do sự kiện cung cấp. Chúng tôi cũng sẽ xác định một bộ lọc bằng cách sử dụng trình so sánh văn bản package0.greater_than_max_uint64 dựa trên cột thời lượng, tính bằng micro giây trong Sự kiện mở rộng, với trạng thái ban đầu là 1000000 hoặc một giây. Với sự bổ sung này cho vị từ, sự kiện sẽ chỉ kích hoạt khi thời lượng vượt quá giá trị ban đầu 1000000 micro giây và sau đó vị từ sẽ lưu trữ giá trị trạng thái mới bên trong, để sự kiện không kích hoạt lại hoàn toàn cho đến khi thời lượng vượt quá giá trị trạng thái bên trong mới. Khi chúng tôi tạo phiên sự kiện, trong trường hợp này sử dụng SQL động vì chúng tôi không thể sử dụng tham số hóa trong các câu lệnh DDL trong SQL Server, phiên sự kiện sẽ được khởi động trên máy chủ và chúng tôi có thể chạy thủ tục lưu trữ mẫu của mình và kiểm soát thời lượng thực thi nhiều lần để xem sự kiện đã kích hoạt như thế nào với vị từ của chúng tôi.

IF EXISTS(SELECT * 
         FROM sys.server_event_sessions 
         WHERE name='StatementExceedsLastDuration') 
    DROP EVENT SESSION [StatementExceedsLastDuration] ON SERVER; 
GO
-- Build the event session using dynamic SQL to concatenate the database_id 
-- and object_id in the DDL, parameterization is not allowed in DDL!
DECLARE @ObjectID    NVARCHAR(10)  = OBJECT_ID('StoredProcedureExceedsDuration'),
              @DatabaseID NVARCHAR(10)   = DB_ID('AdventureWorks2012');
DECLARE @SqlCmd            NVARCHAR(MAX) ='
CREATE EVENT SESSION [StatementExceedsLastDuration] ON SERVER
ADD EVENT sqlserver.module_end(
       SET collect_statement = 1
       WHERE  (object_id = ' + @ObjectID + ' AND 
                      source_database_id = ' + @DatabaseID + ' AND
                     package0.greater_than_max_uint64(duration, 1000000)))
ADD TARGET package0.ring_buffer(SET max_events_limit=10);'
 
EXECUTE(@SqlCmd)
 
ALTER EVENT SESSION [StatementExceedsLastDuration]
ON SERVER
STATE=START;
 
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration '00:00:01.000';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration '00:00:02.000';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration '00:00:01.000';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;

Nếu bạn đọc blog của tôi trên SQLskills.com, bạn có thể biết rằng tôi không phải là người thích sử dụng mục tiêu ring_buffer trong Sự kiện mở rộng vì một số lý do. Đối với việc thu thập dữ liệu hạn chế này và thực tế là phiên sự kiện giới hạn nó ở mức tối đa mười sự kiện, đây là một mục tiêu dễ dàng để chứng minh hành vi của thứ tự vị từ sự kiện, nhưng chúng tôi vẫn cần phải chia nhỏ XML cho các sự kiện theo cách thủ công để xem kết quả.

-- Shred events out of the target
SELECT
    event_data.value('(@name)[1]', 'nvarchar(50)') AS event_name,
    event_data.value('(@timestamp)[1]', 'datetime2') AS [timestamp],
    event_data.value('(data[@name="duration"]/value)[1]', 'bigint') as duration,
    event_data.value('(data[@name="statement"]/value)[1]', 'varchar(max)') as [statement]
FROM (  SELECT CAST(target_data AS xml) AS TargetData
        FROM sys.dm_xe_sessions AS s
        INNER JOIN sys.dm_xe_session_targets AS t
            ON s.address = t.event_session_address
        WHERE s.name = N'StatementExceedsLastDuration'
          AND t.target_name = N'ring_buffer' ) AS tab
CROSS APPLY TargetData.nodes (N'RingBufferTarget/event') AS evts(event_data);

Chạy đoạn mã trên sẽ chỉ dẫn đến 2 sự kiện, một sự kiện diễn ra trong một giây và sau đó là sự kiện khác trong hai giây thực thi. Các lần thực thi khác của thủ tục được lưu trữ ngắn hơn bộ lọc thời lượng một giây ban đầu được chỉ định bằng micro giây trong vị từ và sau đó lần thực thi một giây cuối cùng có thời lượng ngắn hơn giá trị trạng thái được lưu trữ là hai giây bởi trình so sánh. Đây là hành vi dự kiến ​​của tập hợp sự kiện, nhưng nếu chúng tôi thay đổi thứ tự vị từ để bộ lọc package0.greater_than_max_uint64 (thời lượng, 1000000) xảy ra đầu tiên theo thứ tự vị từ và tạo thủ tục được lưu trữ thứ hai mà chúng tôi thực thi với thời lượng là ba giây đầu tiên, chúng tôi sẽ không nhận được bất kỳ sự kiện nào.

USE AdventureWorks2012
GO
IF OBJECT_ID(N'StoredProcedureExceedsDuration') IS NOT NULL
       DROP PROCEDURE dbo.StoredProcedureExceedsDuration;
GO
CREATE PROCEDURE dbo.StoredProcedureExceedsDuration
( @WaitForValue varchar(12) = '00:00:00:050')
AS
       WAITFOR DELAY @WaitForValue;      
GO
IF OBJECT_ID(N'StoredProcedureExceedsDuration2') IS NOT NULL
       DROP PROCEDURE dbo.StoredProcedureExceedsDuration2;
GO
CREATE PROCEDURE dbo.StoredProcedureExceedsDuration2
( @WaitForValue varchar(12) = '00:00:00:050')
AS
       WAITFOR DELAY @WaitForValue;      
GO
IF EXISTS(SELECT * 
         FROM sys.server_event_sessions 
         WHERE name='StatementExceedsLastDuration') 
    DROP EVENT SESSION [StatementExceedsLastDuration] ON SERVER; 
GO
-- Build the event session using dynamic SQL to concatenate the database_id 
-- and object_id in the DDL, parameterization is not allowed in DDL!
DECLARE @ObjectID    NVARCHAR(10)  = OBJECT_ID('StoredProcedureExceedsDuration'),
              @DatabaseID NVARCHAR(10)   = DB_ID('AdventureWorks2012');
DECLARE @SqlCmd            NVARCHAR(MAX) ='
CREATE EVENT SESSION [StatementExceedsLastDuration] ON SERVER
ADD EVENT sqlserver.module_end(
       SET collect_statement = 1
       WHERE  (package0.greater_than_max_uint64(duration, 1000000) AND
                     object_id = ' + @ObjectID + ' AND 
                      source_database_id = ' + @DatabaseID + '))
ADD TARGET package0.ring_buffer(SET max_events_limit=10);'
 
EXECUTE(@SqlCmd)
 
ALTER EVENT SESSION [StatementExceedsLastDuration]
ON SERVER
STATE=START;
 
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration2 '00:00:03.050';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration '00:00:01.050';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration '00:00:02.050';
EXECUTE AdventureWorks2012.dbo.StoredProcedureExceedsDuration;

Trong trường hợp này, vì trình so sánh duy trì trạng thái xảy ra đầu tiên trong thứ tự vị từ, giá trị bên trong của nó được tăng lên khi thực hiện ba giây thứ hai của thủ tục được lưu trữ thứ hai mặc dù sự kiện sau đó không thành công bộ lọc object_id của vị từ và không kích hoạt hoàn toàn. Hành vi này xảy ra với mọi trạng thái duy trì vị từ trong Sự kiện mở rộng. Trước đây tôi đã phát hiện ra hành vi này với cột nguồn vị ngữ package0.counter, nhưng không nhận ra rằng hành vi đó xảy ra đối với bất kỳ phần nào của vị từ duy trì trạng thái. Trạng thái bên trong sẽ thay đổi ngay sau khi phần đó của vị từ được đánh giá. Vì lý do này, bất kỳ bộ lọc vị từ nào thay đổi hoặc duy trì trạng thái phải là phần cuối cùng tuyệt đối của định nghĩa vị từ để đảm bảo nó chỉ sửa đổi trạng thái bên trong khi tất cả các điều kiện vị từ đã được đánh giá.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng biểu thức để lọc dữ liệu của cơ sở dữ liệu

  2. Sử dụng Trình điều khiển ODBC Easysoft với Informatica PowerCenter

  3. Cách xóa hàng trong SQL

  4. Kết nối Ứng dụng 32-bit với jBASE

  5. Làm thế nào để sử dụng câu lệnh bảng thay thế trong SQL?