Lời nói đầu
Dù sớm hay muộn, quản trị viên DB cũng muốn có một chỉ báo hiệu suất cho các truy vấn SQL Server. Như chúng ta đã biết, chạy Profiler trong 24 giờ sẽ dẫn đến tải hệ thống đáng kể và do đó, nó không thể được coi là giải pháp tối ưu cho cơ sở dữ liệu được sử dụng ở chế độ 24/7.
Vì vậy, làm thế nào chúng ta có thể phát hiện trạng thái của các truy vấn SQL Server? Làm cách nào để chúng tôi có thể chạy theo dõi các vấn đề liên quan đến truy vấn đã phát hiện mà không cần con người nhập?
Trong bài viết này, tôi sẽ cung cấp cách triển khai chỉ báo hiệu suất SQL Server cho các truy vấn, thủ tục được lưu trữ và trình kích hoạt, cũng như cách sử dụng nó cho quá trình chạy theo dõi.
Giải pháp
Trước hết, hãy xem cách tiếp cận chung để triển khai chỉ báo hiệu suất cho các truy vấn, thủ tục được lưu trữ và trình kích hoạt:
- Tạo các bảng bắt buộc để thu thập và phân tích thông tin.
- Tạo chế độ xem để thu thập thông tin.
- Tạo các thủ tục được lưu trữ để thu thập thông tin.
- Tạo chế độ xem cho đầu ra thông tin.
Và bây giờ, hãy xem xét việc triển khai:
1. Tạo các bảng cần thiết để thu thập và phân tích thông tin.
1.1. Đối với các truy vấn:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOSET ANSI_PADDING ONGOCREATE TABLE [srv]. [SQL_StatementExecStat] ([ID] [bigint] IDENTITY (1,1) NOT NULL, [InsertDate] [datetime] NULL] binary] (8) NULL, [ExecutionCount] [bigint] NULL, [TotalWorkerTime] [bigint] NULL, [StatementText] [nvarchar] (max) NULL, [TotalElapsedTime] [bigint] NULL, CONSTRAINT [PK_SQL_StatementExecStat] PRIMARY KEY CLUSTERED ( [ID] ASC) WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GOSET ANSI_PADDING1.2. Đối với các thủ tục được lưu trữ:
USE [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER BẢNG ONGOCREATE [srv]. [SQL_ProcedureExecStat] ([ID] [bigint] IDENTITY (1,1) NOT NULL, [InsertDate] [datetime] NULL, [database_id] [int] NULL, [object_id] [int] NULL, [ExecutionCount] [bigint] NULL, [TotalWorkerTime] [bigint] NULL, [TotalElapsedTime] [bigint] NULL, [TotalPhysicalReads] [bigint] NULL, [TotalLogicalReads] [bigint] NULL, [TotalLogicalWrites] [bigint] NULL, CONSTRAINT [PK_SQL_ProcedureExecStat] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS] ON_LOCKS_ ALLOW CHÍNH] ĐI1.3. Đối với trình kích hoạt:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER BẢNG ONGOCREATE [srv]. [SQL_TriggerExecStat] ([ID] [bigint] IDENTITY (1,1) NOT NULL, [InsertDate] [datetime] NULL, [database_id] [int] NULL, [object_id] [int] NULL, [ExecutionCount] [bigint] NULL, [TotalWorkerTime] [bigint] NULL, [TotalElapsedTime] [bigint] NULL) BẬT [CHÍNH] ĐI2. Tạo chế độ xem để thu thập thông tin (ở đây chúng ta có thể chèn các bộ lọc để loại bỏ thông tin không liên quan (ví dụ:truy vấn và thủ tục có trình kích hoạt sao chép, v.v.).
2.1. Đối với truy vấn:SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE chế độ xem [srv]. [vStatementExecInfo] với thông tin dưới dạng (SELECT query_stats.query_hash AS QueryHash, SUM (query_stats.total_worker_timestount) query_stats.execution_count) AS ExecutionCount, SUM (query_stats.total_worker_time) AS TotalWorkerTime, MIN (query_stats.statement_text) AS StatementText, MIN (query_stats.min_worker_time) AS MinWorkerTime, MAX (query_tork_time_max, Max TotalPhysicalReads, MIN (query_stats.min_physical_reads) AS MinPhysicalReads, MAX (query_stats.max_physical_reads) AS MaxPhysicalReads, SUM (query_stats.total_physical_reads) / SUM (query_stats.execution_count) AS AvgPhysicalReads, SUM (query_stats.total_logical_writes) AS TotalLogicalWrites, MIN (query_stats.min_logical_writes) AS MinLogicalWrites, MAX (query_stats.max_logical_writes) AS MaxLogicalWrites, SUM (query_stats.total_stats_writes) total_logical_reads) AS TotalLogicalReads, MIN (query_stats.min_logical_reads) AS MinLogicalReads, MAX (query_stats.max_logical_reads) AS MaxLogicalReads, SUM (query_stats.total_logical_reads) / SUM (query_stats.execution_apsed_count) query_stats.min_elapsed_time) AS MinElapsedTime, MAX (query_stats.max_elapsed_time) AS MaxElapsedTime, SUM (query_stats.total_elapsed_time) / SUM (query_stats.execution_count) AS Av gElapsedTime, MIN (query_stats.creation_time) AS MinCreationTime, MAX (query_stats.last_execution_time) AS LastExecuteTimeFROM (SELECT QS.query_hash, QS.total_worker_time, QS.execution_count, QS.min_worker_ time .total_physical_reads, QS.total_logical_writes, QS.min_logical_writes, QS.max_logical_writes, QS.min_logical_reads, QS.max_logical_reads, QS.total_logical_reads, QS.min_elapsed_time, QS.max_elapsed_time, QS.total , QS.creation_time, QS.last_execution_time, SUBSTRING (ST.text, (QS.statement_start_offset / 2) + 1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH (ST.text) ELSE QS.statement_end_offset END - QS.statement_st) 2) + 1) AS statement_text FROM sys.dm_exec_query_stats AS QS CROSS ÁP DỤNG sys.dm_exec_sql_text (QS.sql_handle) as ST) as query_statsWHERE execute_count> 1and last_execution_time> =dateadd (giờ, -3, getdate ()) ) chọn QueryHash, AvgCPU_Time, ExecutionCount, TotalWorkerTime, StatementText, MinWorkerTime, MaxWorkerTime, TotalPhysicalReads, MinPhysicalReads, MaxPhysicalReads, AvgPhysicalReads, TotalLogicalWrites, MinLogicalLrites, MinPhysicalLeads AvgLogicalReads, TotalElapsedTime, MinElapsedTime, MaxElapsedTime, AvgElapsedTime, MinCreationTime, LastExecuteTimefrom infoGOTại đây, các truy vấn hệ thống sau được sử dụng:sys.dm_exec_query_stats và sys.dm_exec_sql_text.
2.2. Đối với các thủ tục được lưu trữ:SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE chế độ xem [srv]. [vProcedureExecInfo] như với thông tin dưới dạng (SELECT procedure_stats.database_id AS database_id, procedure_stats.object_id AS object_id, MIN (procedure_stats.type) .total_worker_time) / SUM (procedure_stats.execution_count) AS AvgCPU_Time, SUM (procedure_stats.execution_count) AS ExecutionCount, SUM (procedure_stats.total_worker_time) AS TotalWorkerTime, MIN (procedure_erstats.ProcedureTorkT thời gian (procedure_stats.max_worker_time) AS MaxWorkerTime, SUM (procedure_stats.total_physical_reads) AS TotalPhysicalReads, MIN (procedure_stats.min_ph ysical_reads) AS MinPhysicalReads, MAX (procedure_stats.max_physical_reads) AS MaxPhysicalReads, SUM (procedure_stats.total_physical_reads) / SUM (procedure_stats.execution_count) AS AvgPhysicalReads, SUM (procedure_strite procedure_stats.max_logical_writes) AS MaxLogicalWrites, SUM (procedure_stats.total_logical_writes) / SUM (procedure_stats.execution_count) AS AvgLogicalWrites, SUM (procedure_stats.total_logical_reads) AS TotalLogicalReads thủ tục, MIN (procedure_eadicals, MAXLead SUM (procedure_stats.total_logical_reads) / SUM (procedure_stats.execution_count) AS AvgLogicalReads, SUM (procedure_stats.total_elap sed_time) AS TotalElapsedTime, MIN (procedure_stats.min_elapsed_time) AS MinElapsedTime, MAX (thủ tục_stats.max_elapsed_time) AS MaxElapsedTime, SUM (procedure_stats.total_elapsed_time) / SUM (procedure_achedstats.execution_count_time) AS Thời gian trung bình (MAX) procedure_stats.last_execution_time) AS LastExecuteTimeFROM (SELECT QS.database_id, QS.object_id, QS.type, QS.total_worker_time, QS.execution_count, QS.min_worker_time, QS.max_worker_time, QS.object_id, QS.type, QS.total_worker_time, QS.execution_count, QS.min_worker_time, QS.max_worker_time, QS.min_physical_reads, QS.max total_logical_writes, QS.min_logical_writes, QS.max_logical_writes, QS.min_logical_reads, QS.max_logical_reads, QS.total_logical_reads, QS.min_elapsed_time, QS.max_elapsed_time, QS.total_elapsed_time, QS.cached_time, QS.last_execats_time, QS.last_extextProcess_time, QS.last_execats_time. QS CROSS ÁP DỤNG sys.dm_exec_sql_text (QS.sql_handle) as ST) as procedure_statsWHERE execute_count> 1and last_execution_time> =dateadd (giờ, -3, getdate ()) GROUP BY database_id, object_id) select database_id, object_id, type, AvgCPU_Tid TotalWorkerTime, ProcedureText, MinWorkerTime, MaxWorkerTime, TotalPhysicalReads, MinPhysicalReads, MaxPhysicalRead s, AvgPhysicalReads, TotalLogicalWrites, MinLogicalWrites, MaxLogicalWrites, AvgLogicalWrites, TotalLogicalReads, MinLogicalReads, MaxLogicalReads, AvgLogicalReads, TotalElapsedTached, MinElapsedTime, Thời gian tối đaTại đây, các truy vấn hệ thống sau được sử dụng:sys.dm_exec_Procedure_stats và sys.dm_exec_sql_text.
2.3. Đối với trình kích hoạt:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE xem [srv]. [vTriggerExecInfo] với thông tin là (SELECT procedure_stats.database_id AS database_id, procedure_stats.object_id AS object_id, MIN (procedure_stats.type) .total_worker_time) / SUM (procedure_stats.execution_count) AS AvgCPU_Time, SUM (procedure_stats.execution_count) AS ExecutionCount, SUM (procedure_stats.total_worker_time) AS TotalWorkerTime, MIN (procedure_erstats.ProcedureTorkT thời gian (procedure_stats.max_worker_time) AS MaxWorkerTime, SUM (procedure_stats.total_physical_reads) AS TotalPhysicalReads, MIN (procedure_stats.min_phys ical_reads) AS MinPhysicalReads, MAX (procedure_stats.max_physical_reads) AS MaxPhysicalReads, SUM (procedure_stats.total_physical_reads) / SUM (procedure_stats.execution_count) AS AvgPhysicalRritess, SUM (procedure_strites, Minmin.writes) procedure_stats.max_logical_writes) AS MaxLogicalWrites, SUM (procedure_stats.total_logical_writes) / SUM (procedure_stats.execution_count) AS AvgLogicalWrites, SUM (procedure_stats.total_logical_reads) AS TotalLogicalReads thủ tục, MIN (procedure_eadicals, MAXLead SUM (procedure_stats.total_logical_reads) / SUM (procedure_stats.execution_count) AS AvgLogicalReads, SUM (procedure_stats.total_elapse d_time) AS TotalElapsedTime, MIN (procedure_stats.min_elapsed_time) AS MinElapsedTime, MAX (procedure_stats.max_elapsed_time) AS MaxElapsedTime, SUM (procedure_stats.total_elapsed_time) / SUM (procedure_achedstats.execution_count) AS Thời gian trung bình procedure_stats.last_execution_time) AS LastExecuteTimeFROM (SELECT QS.database_id, QS.object_id, QS.type, QS.total_worker_time, QS.execution_count, QS.min_worker_time, QS.max_worker_time, QS.object_id, QS.type, QS.total_worker_time, QS.execution_count, QS.min_worker_time, QS.max_worker_time, QS.min_physical_reads, QS.max total_logical_writes, QS .min_logical_writes, QS.max_logical_writes, QS.min_logical_reads, QS.max_logical_reads, QS.total_logical_reads, QS.min_elapsed_time, QS.max_elapsed_time, QS.total_elapsed_time, QS.cached_time, QS.last_stecation ASTime, QS.last_xtec_text. CROSS ÁP DỤNG sys.dm_exec_sql_text (QS.sql_handle) as ST) as procedure_statsWHERE execute_count> 1and last_execution_time> =dateadd (giờ, -3, getdate ()) GROUP BY database_id, object_id) chọn database_id, object_id, type, AvgCPU_Time, TotalWorkerCountime , Thủ tụcText, MinWorkerTime, MaxWorkerTime, TotalPhysicalReads, MinPhysicalReads, MaxPhysicalReads, AvgPhysicalReads, TotalLogicalWrites, MinLogicalWrites, MaxLogicalWrites, AvgLogicalWrites, TotalLogicalReads, MinLogicalReads, MaxLogicalReads, AvgLogicalReads, TotalElapsedTime, MinElapsedTime, MaxElapsedTime, Thời gian tr.bìnhTại đây, các truy vấn hệ thống sau được sử dụng:sys.dm_exec_trigger_stats và sys.dm_exec_sql_text.
3. Tạo các thủ tục được lưu trữ để thu thập thông tin.
3.1. Đối với các truy vấn:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER QUY TRÌNH ONGOCREATE [srv]. [InsertForSQL_StatementExecStat] @koef decimal (12,2) =0,0 – hệ số thu thập - được chọn theo cách thử nghiệm để thu thập chính xác hơn, - hầu hết trường hợp, chúng ta có thể đặt 0,0, - nếu tần suất chạy bộ sưu tập không quá 5 phút. - Độ chính xác tính toán phụ thuộc vào tần suất thu và hệ số thu. - Chạy bộ sưu tập thường xuyên hơn thì hệ số thu thập ảnh hưởng càng ít. khai báo @AvgCPU_Time bigint, @ MaxAvgCPU_Time bigint, @ AvgTotalWorkerTime bigint, @ MaxTotalWorkerTime bigint, @ AvgAvgElapsedTime bigint, @ MaxAvgElapsedTime bigint, @ AvgTotalElapsedTime bigint, @ MaxTotalWorkerTime bigint, @ AvgAvgElapsedTime bigint, @ MaxAvgElapsedTime bigint, @ AvgTotalElapsedTime @ MaxTimeTime bigint chọn, @ MaxTimeTime @ MaxCPUgTime bigCP AvgtotalworkerTime =avg (TotalWorkerTime), @MoxToTalWorkerTime =Max (TotalWorkerTime), @AvgAvGelapSedTime =avg (avgelap; insert vào srv.SQL_StatementExecStat ([InsertDate], [QueryHash], [ExecutionCount], [TotalWorkerTime], [StatementText], [TotalElapsedTime]) chọn getdate (), [QueryHash], [ExecutionCount], [TotalWorkerTimext], [StatementText] , [TotalElapsedTime] từ srv.vStatementExecInfo trong đó (AvgCPU_Time> @AvgCPU_Time + @koef * (@MaxAvgCPU_Time - @AvgCPU_Time)) hoặc (TotalWorkerTime> @AvgTotalWorkerTime + @koefimetalWorkergTimegTime @ + @koef * (@MaxAvgElapsedTime - @AvgAvgElapsedTime)) hoặc (TotalElapsedTime> @AvgTotalElapsedTime + @koef * (@MaxTotalElapsedTime - @AvgTotalElapsedTime)); ENDGO3.2. Đối với các thủ tục được lưu trữ:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER QUY TRÌNH ONGOCREATE [srv]. [InsertForProcedureExecStat] @koef decimal (12,2) =0,0 - hệ số thu thập - được chọn theo cách thử nghiệm để thu thập chính xác hơn, --in hầu hết các trường hợp, chúng ta có thể đặt 0,0, - nếu tần suất chạy bộ sưu tập không quá 5 phút. - Độ chính xác tính toán phụ thuộc vào tần suất thu và hệ số thu. - Chạy bộ sưu tập thường xuyên hơn thì hệ số thu thập ảnh hưởng càng ít. khai báo @AvgCPU_Time bigint, @ MaxAvgCPU_Time bigint, @ AvgTotalWorkerTime bigint, @ MaxTotalWorkerTime bigint, @ AvgAvgElapsedTime bigint, @ MaxAvgElapsedTime bigint, @ AvgTotalElapsedTime bigint, @ MaxTotalint; chọn @AvgCPU_Time =AVG (AvgCPU_Time), @MaxAvgCPU_Time =max (AvgCPU_Time), @AvgTotalWorkerTime =AVG (TotalWorkerTime), @MaxTotalWorkerTime =max (TotalWorkerTime), @AvgTotalWorkerTime =AVG (Tổng thời gian) AvgTotalElapsedTime =AVG (TotalElapsedTime), @MaxTotalElapsedTime =max (TotalElapsedTime) từ srv.vProcedureExecInfo; chèn vào srv.SQL_ProcedureExecStat ([InsertDate], database_id, object_id, [ExecutionCount], [TotalWorkerTime], [TotalElapsedTime], [TotalPhysicalReads], [TotalLogicalReads], [TotalLogicalWrites]) chọn getdate (), database_id, object_id ExecutionCount , [TotalWorkerTime], [TotalElapsedTime], [TotalPhysicalReads], [TotalLogicalReads], [TotalLogicalWrites] từ srv.vProcedureExecInfo trong đó (AvgCPU_Time> @AvgCPU_Time + @koef * (@MaxAvgCPgTime koef * (@MaxTotalWorkerTime - @AvgTotalWorkerTime)) hoặc (AvgElapsedTime> @AvgAvgElapsedTime + @koef * (@MaxAvgElapsedTime - @AvgAvgElapsedTime)) hoặc (Tổng thời gian apsedTime - @AvgTotalElapsedTime)); ENDGO3.3. Đối với trình kích hoạt:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER QUY TRÌNH ONGOCREATE [srv]. [InsertForTriggerExecStat] @koef decimal (12,2) =0,0 - hệ số thu thập - được chọn theo cách thử nghiệm để thu thập chính xác hơn, --in hầu hết các trường hợp, chúng ta có thể đặt 0,0, - nếu tần suất chạy bộ sưu tập không quá 5 phút. - Độ chính xác tính toán phụ thuộc vào tần suất thu và hệ số thu. - Chạy bộ sưu tập thường xuyên hơn thì hệ số thu thập ảnh hưởng càng ít. khai báo @AvgCPU_Time bigint, @ MaxAvgCPU_Time bigint, @ AvgTotalWorkerTime bigint, @ MaxTotalWorkerTime bigint, @ AvgAvgElapsedTime bigint, @ MaxAvgElapsedTime bigint, @ AvgTotalElapsedTime bigint, @ MaxTotalWorkerTime bigint, @ AvgAvgElapsedTime bigint, @ MaxAvgElapsedTime bigint, @ AvgTotalElapsedTime @ MaxTimeTime bigint chọn, @ MaxTimeTime @ MaxCPUgTime bigCP AvgtotalworkerTime =avg (TotalWorkerTime), @MaXToTalWorkerTime =Max (TotalWorkerTime), @avgavgelapsedtime =avg (avgelapsedtime); insert vào srv.SQL_TriggerExecStat ([InsertDate], database_id, object_id, [ExecutionCount], [TotalWorkerTime], [TotalElapsedTime]) chọn getdate (), database_id, object_id, [ExecutionCount], [TotalWorkerTime], [TotalElapsedvTime] từ srecIn.vTrigger trong đó (AvgCPU_Time> @AvgCPU_Time + @koef * (@MaxAvgCPU_Time - @AvgCPU_Time)) hoặc (TotalWorkerTime> @AvgTotalWorkerTime + @koef * (@MaxTotalWorkerTime - @AvgTotalWorkerTime @Alapsed @AvgAvgElapsedTime)) hoặc (TotalElapsedTime> @AvgTotalElapsedTime + @koef * (@MaxTotalElapsedTime - @AvgTotalElapsedTime)); ENDGO4. Tạo chế độ xem cho đầu ra thông tin.
4.1. Đối với các truy vấn:
USE [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE VIEW [srv]. [vStatementExecTotalInfo] chọn ExecutionCount là Num, TotalWorkerTime as TotalWorkerTime, TotalUElapsedTime as TotalElapsedTime (Thời gian trung bình 10000gCP, chuyển đổi 8,2) chuyển đổi (thập phân (8,2), AvgElapsedTime / 1000000.) thành AvgElapsedSec, ..., QueryHash, StatementText từ [SRV]. [srv]. [vStatementExecInfo]; GO4.2. Đối với các thủ tục được lưu trữ:
USE [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE VIEW [srv]. [vProcedureExecTotalInfo] khi chọn ExecutionCount dưới dạng Num, TotalWorkerTime thành TotalWorkerTime, TotalUElapsedTime thành TotalElapsedTime (Thời gian trung bình 10000gCPer, chuyển đổi 8,2) , chuyển đổi (thập phân (8,2), AvgElapsedTime / 1000000.) thành AvgElapsedSec, ..., database_id, object_id, db_name (database_id) dưới dạng DB_Name, OBJECT_SCHEMA_NAME (object_id, database_id) dưới dạng Schema_Name, object_name (object_id, database_id) dưới dạng Procedure_Name từ [SRV]. [srv]. [vProcedureExecInfo]; ĐI4.3. Chế độ xem cho trình kích hoạt được tạo theo cách tương tự (nếu cần). Đối với tôi, tôi không cần trình kích hoạt theo dõi, vì nếu có bất kỳ sự cố nào với trình kích hoạt, việc thực thi các thủ tục và truy vấn được lưu trữ sẽ hiển thị chúng.
Hai tham số sau có tầm quan trọng thiết yếu đối với các chế độ xem được triển khai:
- AvgWorkerSec - thời gian thực hiện truy vấn tính bằng giây.
- AvgElapsedSec - thời gian chờ hoặc thời gian chờ + AvgWorkerSec.
Đối với kết quả của các lượt xem, sự bình đẳng sau đây là quan trọng:
AvgWorkerSec =AvgElapsedSec
- AvgWorkerSec> AvgElapsedSec - ở đây thứ gì đó tải nặng bộ xử lý vào thời điểm thực thi truy vấn (hóa ra là phần mềm diệt vi-rút đang chạy; đó cũng có thể là lỗi của kế hoạch song song).
- AvgWorkerSec
Nếu AvgWorkerSec =AvgElapsedSec được tuân thủ, thì thời gian thực thi dài có liên quan đến chính truy vấn và thời gian thực thi của nó.
Tiêu chí của việc thực thi truy vấn dài là gì?
Không có câu trả lời tuyệt đối cho câu hỏi này. Nó phụ thuộc vào chức năng của một truy vấn, vị trí và cách nó được sử dụng, v.v.
Tôi có đánh giá sau cho các truy vấn đặc biệt và các thủ tục được lưu trữ:
- Lên đến 0,5 - tốt cho các thủ tục được lưu trữ, không có vấn đề gì (không phải chờ thực thi).
- Lên đến 0,1 - tốt cho các truy vấn, không có vấn đề gì (không đợi thực thi).
- 0,5 - 1,0 - không tốt cho các thủ tục được lưu trữ, có vấn đề (không có thời gian chờ thực thi nào hiển thị cho người dùng, nhưng chúng vẫn tồn tại và yêu cầu giải pháp).
- 0,1 - 0,5 - không tốt cho các truy vấn, có vấn đề (không có thời gian chờ thực thi nào hiển thị cho người dùng, nhưng chúng vẫn tồn tại và yêu cầu giải quyết).
- Hơn 1,0 - không tốt cho các thủ tục được lưu trữ, có vấn đề (rất có thể người dùng phải chờ đợi, vấn đề cần giải pháp ngay lập tức).
- Hơn 0,5 - không tốt cho các truy vấn, có vấn đề (rất có thể người dùng đang chờ có hiển thị, vấn đề cần giải pháp ngay lập tức).
Đối với các truy vấn không đột xuất (tải lên dữ liệu, tải dữ liệu), đánh giá trên được chọn trên cơ sở cá nhân. Thông thường, nó vượt quá nhiều đánh giá cho các truy vấn đặc biệt và các thủ tục được lưu trữ.
Nếu tất cả phần mềm hoạt động thông qua các thủ tục được lưu trữ, bạn chỉ có thể theo dõi các thủ tục đã lưu trữ, vì công việc của các truy vấn luôn ảnh hưởng đến công việc của các thủ tục được lưu trữ. Đó là lý do tại sao, chúng ta hãy giải quyết dựa trên phân tích về việc thực hiện các thủ tục được lưu trữ.
Hãy tạo một hệ thống để thu thập thông tin về các thủ tục được lưu trữ nặng nề nhất để phân tích và chạy tự động liên kết tiếp theo, theo thuật toán sau:
1. Tạo một bảng để lưu trữ thông tin:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER BẢNG ONGOCREATE [srv]. [SQL_TopProcedureExecStat] ([Row_GUID] [uniqueidentifier] NOT NULL, [SERVER] [nvarchar] (255) NOT NULL, [DB_ID] , [OBJECT_ID] [int] NOT NULL, [ExecutionCount] [bigint] NOT NULL, [TotalWorkerTime] [bigint] NULL, [TotalElapsedTime] [bigint] NULL, [Func] [decimal] (8, 2) NULL, [AvgWorkerSec ] [decimal] (8, 2) NULL, [AvgElapsedSec] [decimal] (8, 2) NULL, [DB_NAME] [nvarchar] (255) NULL, [SCHEMA_NAME] [nvarchar] (255) NULL, [OBJECT_NAME] [ nvarchar] (255) NULL, [InsertUTCDate] [datetime] NOT NULL, [TotalPhysicalReads] [bigint] NULL, [TotalLogicalReads] [bigint] NULL, [TotalLogicalWrites] [bigint] NULL, [AvgPhysicalReads] [bigint] NULL, [AvgLog ] [bigint] NULL, [AvgLogicalWrites] [bigint] NULL, [CategoryName] [nvarchar] (255) NULL, CONSTRAINT [PK_ SQL_TopProcedureExecStat] CHÌA KHÓA CHÍNH XÁC ([Row_GUID] ASC) VỚI (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMABLE]. ] THÊM BẢNG MỤC TIÊU [DF_SQL_TopProcedureExecStat_Row_GUID] DEFAULT (newid ()) CHO [Row_GUID] BẢNG MỤC TIÊU [srv]. [SQL_TopProcedureExecStat] THÊM CONSTRAINT [DF_SQL_TopProcedureExecABLE Tên người dùng để bảo vệ [SQL_TopProcedureExecABLEStat_SERVER] @ máy chủ] CONSTRAINT [DF_SQL_TopProcedureExecStat_InsertUTCDate] DEFAULT (getutcdate ()) FOR [InsertUTCDate] GO2. Tạo một quy trình được lưu trữ để thu thập thông tin:
SỬ DỤNG [DATABASE_NAME] GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER QUY TRÌNH ONGOCREATE [srv]. [InsertTopProcedureExecStat] @top tinyint =24 - số ngày để lưu trữ hồ sơ, @ CategoryName nvarchar (255) ='AvgWorkerSec lựa chọnASBEGIN' - một danh mục cho lựa chọn TRÊN; INSERT INTO [srv]. [SQL_TopProcedureExecStat] ([DB_ID], [OBJECT_ID], [ExecutionCount], [TotalWorkerTime], [TotalElapsedTime], [AvgWorkerSec], [AvgElapsedSec], [DB_NAME], [SCHEMA_NAME], InsertUTCDate, CategoryName, TotalPhysicalReads, TotalLogicalReads, TotalLogicalWrites, AvgPhysicalReads, AvgLogicalReads, AvgLogicalWrites) chọn hàng đầu (@top) [database_id], [object_id], [Num], [TotalWorkerTime], AvgTime, [TotalElapsed], [TotalElapsed], [TotalElapsed], [TotalElapsed], [TotalElapsed] [DB_NAME] ,[SCHEMA_NAME] ,[PROCEDURE_NAME] ,InsertUTCDate ,C ategoryName ,TotalPhysicalReads ,TotalLogicalReads ,TotalLogicalWrites ,AvgPhysicalReads ,AvgLogicalReads ,AvgLogicalWrites from( select [database_id] ,[object_id] ,[Num] ,[TotalWorkerTime] ,[TotalElapsedTime] ,[AvgWorkerSec] ,[AvgElapsedSec] ,[DB_NAME] ,[SCHEMA_NAME] ,[PROCEDURE_NAME] ,getUTCDate() as InsertUTCDate ,@CategoryName as CategoryName ,TotalPhysicalReads ,TotalLogicalReads ,TotalLogicalWrites ,AvgPhysicalReads ,AvgLogicalReads ,AvgL ogicalWrites FROM [srv].[vProcedureExecTotalInfoHour] ) as t order by case @CategoryName when 'TotalWorkerTime' then TotalWorkerTime when 'TotalElapsedTime' then TotalElapsedTime when 'AvgWorkerSec' then AvgWorkerSec when 'AvgElapsedSec' then AvgElapsedSec when 'TotalPhysicalReads' then TotalPhysicalReads when 'TotalLogicalReads' then TotalLogicalReads when 'TotalLogicalWrites' then TotalLogicalWrites when 'AvgPhysicalReads' then AvgPhysicalReads when 'AvgLogicalReads' then AvgLogicalReads when 'AvgLogicalWrites' then AvgLogicalWrites end desc; declare @count int=(select count(*) from [srv].[SQL_TopProcedureExecStat] where [email protected]); declare @diff [email protected]@top;;with tbl_del as( select Row_GUID from [srv].[SQL_TopProcedureExecStat] where InsertUTCDate0) begin;with tbl_del as( select top(@diff) Row_GUID from [srv].[SQL_TopProcedureExecStat] where [email protected] order by case @CategoryName when 'TotalWorkerTime' then TotalWorkerTime when 'TotalElapsedTime' then TotalElapsedTime when 'AvgWorkerSec' then AvgWorkerSec when 'AvgElapsedSec' then AvgElapsedSec when 'TotalPhysicalReads' then TotalP hysicalReads when 'TotalLogicalReads' then TotalLogicalReads when 'TotalLogicalWrites' then TotalLogicalWrites when 'AvgPhysicalReads' then AvgPhysicalReads when 'AvgLogicalReads' then AvgLogicalReads when 'AvgLogicalWrites' then AvgLogicalWrites end ) delete from [srv].[SQL_TopProcedureExecStat] where Row_GUID in (select Row_GUID from tbl_del); end declare @DB_ID int declare @OBJECT_ID int declare @top1 int =3 declare @diff1 int declare @count1 int -- deletion of more than @top1 times repeats of the specific procedure select top (1) @count1 =tp.num ,@DB_ID =tp.DB_ID ,@OBJECT_ID =tp.OBJECT_ID from (select count(*) as num, DB_ID, OBJECT_ID from [srv].[SQL_TopProcedureExecStat] where [email protected] group by DB_ID, OBJECT_ID) as tp order by tp.num desc; set @diff1 =@count1 - @top1; if(@diff1)> 0 begin;with tbl_del as( select top(@diff1) Row_GUID from [srv].[SQL_TopProcedureExecStat] where DB_ID =@DB_ID and OBJECT_ID =@OBJECT_ID and [email protected] order by case @CategoryName when 'TotalWorkerTime' then TotalWorkerTime when 'TotalElapsedTime' then TotalElapsedTime when 'AvgWorkerSec' then AvgWorkerSec when 'AvgElapsedSec' then AvgElapsedSec when 'TotalPhysicalReads' then TotalPhysicalReads when 'TotalLogicalReads' then Tot alLogicalReads when 'TotalLogicalWrites' then TotalLogicalWrites when 'AvgPhysicalReads' then AvgPhysicalReads when 'AvgLogicalReads' then AvgLogicalReads when 'AvgLogicalWrites' then AvgLogicalWrites end ) delete from [srv].[SQL_TopProcedureExecStat] where Row_GUID in (select Row_GUID from tbl_del); end -- deletion of more than 1 repeats of the AvgWorkerSec parameter for the specific procedure if @CategoryName ='AvgWorkerSec' begin declare @AvgWorkerSec decimal(8,2) select top (1) @count1 =tp.num ,@DB_ID =tp.DB_ID ,@OBJECT_ID =tp.OBJECT_ID ,@AvgWorkerSec =tp.AvgWorkerSec from (select count(*) as num, DB_ID, OBJECT_ID, AvgWorkerSec from [srv].[SQL_TopProcedureExecStat] where [email protected] group by DB_ID, OBJECT_ID,AvgWorkerSec) as tp order by tp.num desc; set @diff1 =@count1 - 1; if(@diff1)> 0 begin;with tbl_del as( select top(@diff1) Row_GUID from [srv].[SQL_TopProcedureExecStat] where DB_ID =@DB_ID and OBJECT_ID =@OBJECT_ID and [email protected] and AvgWorkerSec =@AvgWorkerSec order by InsertUTCDate desc ) delete from [srv].[SQL_TopProcedureExecStat] where Row_GUID in (select Row_GUID from tbl_del); end end if @CategoryName ='AvgElapsedSec' begin declare @AvgElapsedSec decimal(8,2) select top (1) @count1 =tp.num ,@DB_ID =tp.DB_ID ,@OBJECT_ID =tp.OBJECT_ID ,@AvgElapsedSec =tp.AvgElapsedSec from (select count(*) as num, DB_ID, OBJECT_ID, AvgElapsedSec from [srv].[SQL_TopProcedureExecStat] where [email protected] group by DB_ID, OBJECT_ID,AvgElapsedSec) as tp order by tp.num desc; set @diff1 =@count1 - 1; if(@diff1)> 0 begin;with tbl_del as( select top(@diff1) Row_GUID from [srv].[SQL_TopProcedureExecStat] where DB_ID =@DB_ID and OBJECT_ID =@OBJECT_ID and [email protected] and AvgElapsedSec =@AvgElapsedSec order by InsertUTCDate desc ) delete from [srv].[SQL_TopProcedureExecStat] where Row_GUID in (select Row_GUID from tbl_del); end endENDGO It is better to run this stored procedure immediately after collecting information about the stored procedures (we can set up a task in Agent for running it every 5-10 minutes for queries, stored procedures and triggers):
exec [srv].[InsertForSQL_StatementExecStat]; --collecting information about executed queriesexec [srv].[InsertForTriggerExecStat]; --collecting information about executed triggersexec [srv].[InsertForProcedureExecStat]; --collecting information about executed stored procedures--collecting information about the most heavy executed stored procedures, according to the criteriaexec [srv].[InsertTopProcedureExecStat] @[email protected], @CategoryName='AvgWorkerSec';exec [srv].[InsertTopProcedureExecStat] @[email protected], @CategoryName='AvgElapsedSec'3. Running trace (every 5-10 minutes with the help of the Agent tasks, preferably right after collecting information):
USE [DATABASE_NAME];go--coefficient of transition value of indicatordeclare @koef_red numeric(8,3)=1.3; --if there are records with the indicator greater than or equal to the --preset indicator coefficient if(exists( SELECT top(1) 1 FROM [srv].[SQL_TopProcedureExecStat] where CategoryName='AvgElapsedSec' or CategoryName='AvgWorkerSec' group by CategoryName having avg([AvgElapsedSec])>[email protected]_red or avg([AvgWorkerSec])>[email protected]_red)) begin --running autorace exec .[srv].[AutoTrace]; endThe auto-trace stored procedure is implemented on an individual basis. Ví dụ:
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[AutoTrace] @maxfilesize bigint=200 --maximum file size in Mb ,@run_minutes int=60 --tracing length in minutes ,@file_patch nvarchar(255)=N'Path to directory' --directory for trace file ,@file_name nvarchar(255)=N'Profiler' --file name ,@res_msg nvarchar(255)=NULL output --result in the form of messagesASBEGIN SET NOCOUNT ON; declare @rc int; declare @TraceID int; if(@run_minutes>=1200) set @run_minutes=1200; --no longer than 20 hours! declare @finish_dt datetime=DateAdd(minute,@run_minutes,GetDate()); --execution end time --end of trace file declare @finish_dt_inc nvarchar(255)=N'_'+cast(YEAR(@finish_dt) as nvarchar(255))+'_'+cast(MONTH(@finish_dt) as nvarchar(255))+'_'+cast(DAY(@finish_dt) as nvarchar(255)); declare @File nvarchar(255)[email protected]@[email protected]_dt_inc; --full name of the trace file DECLARE @result bit; DECLARE @msgerrors nvarchar(255); DECLARE @oldDT datetime; --Getting the last date and time if(object_id('DATABASE_NAME.dbo.TraceTable')<>0) begin select @oldDT=max(StartTime) from DATABASE_NAME.dbo.TraceTable where StartTime is not null; end --select @oldDT; --If the last date and time is not specified or it is less than time of trace ending,trace is run. Otherwise, the trace was executed on this date. if(@oldDT is null or @oldDT=10) set @run_delay_hour_str=cast(@run_delay_hour as nvarchar(255)); --select @run_delay_hour, @run_delay_hour_str; --adding missing nulls for string representation of minutes if(@run_delay_minute=0) set @run_delay_minute_str='00'; else if(@run_delay_minute<10) set @run_delay_minute_str='0'+cast(@run_delay_minute as nvarchar(255)); else if(@run_delay_minute>=10) set @run_delay_minute_str=cast(@run_delay_minute as nvarchar(255)); --select @run_delay_minute, @run_delay_minute_str; --the hours:minutes string representation for the wait declare @run_delay_str nvarchar(255)[email protected]_delay_hour_str+':'[email protected]_delay_minute_str; --wait WAITFOR DELAY @run_delay_str; --select @run_delay_str; --deletion of the trace table, if it exists if(object_id('DATABASE_NAME.dbo.TraceTable')<>0) begin drop table DATABASE_NAME.dbo.TraceTable; end --creation and filling of the trace table from the trace file SELECT * INTO DATABASE_NAME.dbo.TraceTable FROM ::fn_trace_gettable(@File+'.trc', default); --adding extension to the full file set @[email protected]+'.trc'; --here, we need to insert code to delete the trace file declare @str_title nvarchar(max)='There was auto trace on the server'[email protected]@servername, @str_pred_mess nvarchar(max)='На '[email protected]@servername+'The auto trace has been run on the server. You can view the result in the Database_Name.dbo.TraceTable table; --here, we can send the auto trace run notification to administrator end --returning the result set @res_msg=N'ErrorCode='+cast(@rc as nvarchar(255))+'\r\n'+coalesce(@msgerrors, ''); endENDGO For more information on setting trace, refer to How to:Create a Trace (Transact-SQL).
Kết luận
In this article, we considered an example of implementation of a system for collecting information about the state of a database, that does not load the system. In case of problem detection, this system runs the preset trace and saves results into a table. This approach can be extended to several servers. In this case, we need to collect information from all servers for subsequent sending of information to administrators.
It is also important to remember about deletion of old data from the used tables. It is quite sufficient to store data within a month or two weeks.
Also read:
Implementing a Common MS SQL Server Performance Indicator
References
- sys.dm_exec_trigger_stats
- sys.dm_exec_procedure_stats
- sys.dm_exec_query_stats
- sys.dm_exec_sql_text
- How to:Create a Trace (Transact-SQL)