Trong Microsoft SQL Server, làm cách nào tôi có thể nhận được một kế hoạch thực hiện truy vấn cho một thủ tục truy vấn / được lưu trữ?
Trong Microsoft SQL Server, làm cách nào tôi có thể nhận được một kế hoạch thực hiện truy vấn cho một thủ tục truy vấn / được lưu trữ?
Câu trả lời:
Có một số phương pháp để có được một kế hoạch thực hiện, phương pháp nào sẽ sử dụng sẽ phụ thuộc vào hoàn cảnh của bạn. Thông thường, bạn có thể sử dụng SQL Server Management Studio để lấy kế hoạch, tuy nhiên nếu vì lý do nào đó bạn không thể chạy truy vấn của mình trong SQL Server Management Studio thì bạn có thể thấy hữu ích khi có thể lấy kế hoạch qua SQL Server Profiler hoặc bằng cách kiểm tra bộ đệm kế hoạch.
SQL Server đi kèm với một số tính năng gọn gàng giúp bạn dễ dàng nắm bắt kế hoạch thực hiện, chỉ cần đảm bảo rằng mục menu "Bao gồm thực thi kế hoạch thực tế" (được tìm thấy trong menu "Truy vấn") được đánh dấu và chạy truy vấn của bạn như bình thường .
Nếu bạn đang cố gắng để có được kế hoạch thực hiện cho các câu lệnh trong một thủ tục được lưu trữ thì bạn nên thực hiện thủ tục được lưu trữ, như vậy:
exec p_Example 42
Khi truy vấn của bạn hoàn tất, bạn sẽ thấy một tab bổ sung có tên "Kế hoạch thực hiện" xuất hiện trong khung kết quả. Nếu bạn đã chạy nhiều báo cáo thì bạn có thể thấy nhiều gói được hiển thị trong tab này.
Từ đây, bạn có thể kiểm tra kế hoạch thực hiện trong SQL Server Management Studio hoặc nhấp chuột phải vào kế hoạch và chọn "Lưu kế hoạch thực hiện dưới dạng ..." để lưu kế hoạch vào một tệp ở định dạng XML.
Phương pháp này rất giống với phương pháp 1 (thực tế đây là những gì SQL Server Management Studio thực hiện), tuy nhiên tôi đã đưa nó vào để hoàn thiện hoặc nếu bạn không có sẵn SQL Server Management Studio.
Trước khi bạn chạy truy vấn của mình, hãy chạy một trong các câu lệnh sau. Câu lệnh phải là câu lệnh duy nhất trong lô, tức là bạn không thể thực thi câu lệnh khác cùng một lúc:
SET SHOWPLAN_TEXT ON
SET SHOWPLAN_ALL ON
SET SHOWPLAN_XML ON
SET STATISTICS PROFILE ON
SET STATISTICS XML ON -- The is the recommended option to use
Đây là các tùy chọn kết nối và vì vậy bạn chỉ cần chạy nó một lần cho mỗi kết nối. Từ thời điểm này, tất cả các câu lệnh chạy sẽ được kèm theo một tập kết quả bổ sung có chứa kế hoạch thực hiện của bạn ở định dạng mong muốn - chỉ cần chạy truy vấn của bạn như bình thường để xem kế hoạch.
Khi bạn đã hoàn tất, bạn có thể tắt tùy chọn này bằng câu lệnh sau:
SET <<option>> OFF
Trừ khi bạn có một ưu tiên mạnh mẽ, khuyến nghị của tôi là sử dụng STATISTICS XML
tùy chọn này. Tùy chọn này tương đương với tùy chọn "Bao gồm kế hoạch thực thi thực tế" trong SQL Server Management Studio và cung cấp nhiều thông tin nhất ở định dạng thuận tiện nhất.
SHOWPLAN_TEXT
- Hiển thị một kế hoạch thực hiện ước tính dựa trên văn bản cơ bản, mà không thực hiện truy vấnSHOWPLAN_ALL
- Hiển thị một kế hoạch thực hiện ước tính dựa trên văn bản với các ước tính chi phí, mà không thực hiện truy vấnSHOWPLAN_XML
- Hiển thị một kế hoạch thực hiện ước tính dựa trên XML với các ước tính chi phí, mà không thực hiện truy vấn. Điều này tương đương với tùy chọn "Hiển thị kế hoạch thực hiện ước tính ..." trong SQL Server Management Studio.STATISTICS PROFILE
- Thực hiện truy vấn và hiển thị một văn bản dựa trên kế hoạch thực hiện.STATISTICS XML
- Thực hiện truy vấn và hiển thị kế hoạch thực hiện thực tế dựa trên XML. Điều này tương đương với tùy chọn "Bao gồm kế hoạch thực hiện thực tế" trong SQL Server Management Studio.Nếu bạn không thể chạy truy vấn của mình trực tiếp (hoặc truy vấn của bạn không chạy chậm khi bạn thực hiện trực tiếp - hãy nhớ rằng chúng tôi muốn một kế hoạch truy vấn hoạt động kém), thì bạn có thể nắm bắt một kế hoạch bằng cách sử dụng theo dõi SQL Server Profiler. Ý tưởng là để chạy truy vấn của bạn trong khi một dấu vết đang nắm bắt một trong những sự kiện "Showplan" đang chạy.
Lưu ý rằng tùy thuộc vào tải, bạn có thể sử dụng phương pháp này trên môi trường sản xuất, tuy nhiên rõ ràng bạn nên thận trọng. Các cơ chế lược tả SQL Server được thiết kế để giảm thiểu tác động lên cơ sở dữ liệu nhưng điều này không có nghĩa là sẽ không có bất kỳ tác động hiệu suất nào . Bạn cũng có thể gặp vấn đề khi lọc và xác định kế hoạch chính xác trong dấu vết của mình nếu cơ sở dữ liệu của bạn đang được sử dụng nhiều. Bạn rõ ràng nên kiểm tra với DBA của bạn để xem họ có hài lòng với bạn khi làm điều này trên cơ sở dữ liệu quý giá của họ không!
Gói bạn nhận được tương đương với tùy chọn "Bao gồm Kế hoạch thực hiện thực tế" trong SQL Server Management Studio.
Nếu bạn không thể chạy truy vấn của mình trực tiếp và bạn cũng không thể nắm bắt được dấu vết hồ sơ thì bạn vẫn có thể có được một kế hoạch ước tính bằng cách kiểm tra bộ đệm của kế hoạch truy vấn SQL.
Chúng tôi kiểm tra bộ đệm của kế hoạch bằng cách truy vấn DMV của SQL Server . Sau đây là một truy vấn cơ bản sẽ liệt kê tất cả các gói truy vấn được lưu trong bộ nhớ cache (dưới dạng xml) cùng với văn bản SQL của chúng. Trên hầu hết các cơ sở dữ liệu, bạn cũng sẽ cần thêm các mệnh đề lọc bổ sung để lọc kết quả xuống chỉ các kế hoạch bạn quan tâm.
SELECT UseCounts, Cacheobjtype, Objtype, TEXT, query_plan
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
CROSS APPLY sys.dm_exec_query_plan(plan_handle)
Thực hiện truy vấn này và nhấp vào kế hoạch XML để mở kế hoạch trong một cửa sổ mới - nhấp chuột phải và chọn "Lưu kế hoạch thực hiện dưới dạng ..." để lưu kế hoạch vào tệp ở định dạng XML.
Vì có rất nhiều yếu tố liên quan (từ lược đồ bảng và chỉ mục cho đến dữ liệu được lưu trữ và thống kê bảng), bạn nên luôn cố gắng có được một kế hoạch thực hiện từ cơ sở dữ liệu mà bạn quan tâm (thông thường là một trong số đó đang trải qua hiệu suất vấn đề).
Bạn không thể nắm bắt một kế hoạch thực hiện cho các thủ tục lưu trữ được mã hóa.
Một kế hoạch thực hiện thực tế là một trong đó SQL Server thực sự chạy truy vấn, trong khi đó một kế hoạch thực hiện ước tính SQL Server sẽ thực hiện những gì nó sẽ làm mà không cần thực hiện truy vấn. Mặc dù tương đương về mặt logic, một kế hoạch thực hiện thực tế hữu ích hơn nhiều vì nó chứa các chi tiết và thống kê bổ sung về những gì thực sự đã xảy ra khi thực hiện truy vấn. Điều này rất cần thiết khi chẩn đoán các vấn đề trong đó ước tính Máy chủ SQL bị tắt (chẳng hạn như khi hết số liệu thống kê).
Đây là một chủ đề đủ xứng đáng cho một cuốn sách (miễn phí) theo đúng nghĩa của nó.
SET STATISTICS XML ON
ant vào đầu truy vấn và SET STATISTICS XML OFF|ON
các khu vực xung quanh bạn không muốn hiển thị trong đầu ra của kế hoạch: Tôi thấy điều này hữu ích khi truy vấn chứa một lần lặp (WHILE) mà bạn không muốn / cần để xem trong kế hoạch thực hiện (nếu không, nó sẽ quá nặng và lâu để SQL SERVER hiển thị nó).
Ngoài câu trả lời toàn diện đã được đăng đôi khi rất hữu ích khi có thể truy cập kế hoạch thực hiện theo chương trình để trích xuất thông tin. Mã ví dụ cho điều này là dưới đây.
DECLARE @TraceID INT
EXEC StartCapture @@SPID, @TraceID OUTPUT
EXEC sp_help 'sys.objects' /*<-- Call your stored proc of interest here.*/
EXEC StopCapture @TraceID
StartCapture
Định nghĩa ví dụCREATE PROCEDURE StartCapture
@Spid INT,
@TraceID INT OUTPUT
AS
DECLARE @maxfilesize BIGINT = 5
DECLARE @filepath NVARCHAR(200) = N'C:\trace_' + LEFT(NEWID(),36)
EXEC sp_trace_create @TraceID OUTPUT, 0, @filepath, @maxfilesize, NULL
exec sp_trace_setevent @TraceID, 122, 1, 1
exec sp_trace_setevent @TraceID, 122, 22, 1
exec sp_trace_setevent @TraceID, 122, 34, 1
exec sp_trace_setevent @TraceID, 122, 51, 1
exec sp_trace_setevent @TraceID, 122, 12, 1
-- filter for spid
EXEC sp_trace_setfilter @TraceID, 12, 0, 0, @Spid
-- start the trace
EXEC sp_trace_setstatus @TraceID, 1
StopCapture
Định nghĩa ví dụCREATE PROCEDURE StopCapture
@TraceID INT
AS
WITH XMLNAMESPACES ('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as sql),
CTE
as (SELECT CAST(TextData AS VARCHAR(MAX)) AS TextData,
ObjectID,
ObjectName,
EventSequence,
/*costs accumulate up the tree so the MAX should be the root*/
MAX(EstimatedTotalSubtreeCost) AS EstimatedTotalSubtreeCost
FROM fn_trace_getinfo(@TraceID) fn
CROSS APPLY fn_trace_gettable(CAST(value AS NVARCHAR(200)), 1)
CROSS APPLY (SELECT CAST(TextData AS XML) AS xPlan) x
CROSS APPLY (SELECT T.relop.value('@EstimatedTotalSubtreeCost',
'float') AS EstimatedTotalSubtreeCost
FROM xPlan.nodes('//sql:RelOp') T(relop)) ca
WHERE property = 2
AND TextData IS NOT NULL
AND ObjectName not in ( 'StopCapture', 'fn_trace_getinfo' )
GROUP BY CAST(TextData AS VARCHAR(MAX)),
ObjectID,
ObjectName,
EventSequence)
SELECT ObjectName,
SUM(EstimatedTotalSubtreeCost) AS EstimatedTotalSubtreeCost
FROM CTE
GROUP BY ObjectID,
ObjectName
-- Stop the trace
EXEC sp_trace_setstatus @TraceID, 0
-- Close and delete the trace
EXEC sp_trace_setstatus @TraceID, 2
GO
Giả sử bạn đang sử dụng Microsoft SQL Server Management Studio
Bên cạnh các phương thức được mô tả trong các câu trả lời trước đó, bạn cũng có thể sử dụng trình xem kế hoạch thực hiện miễn phí và công cụ tối ưu hóa truy vấn ApexQuery Plan (mà gần đây tôi đã gặp phải).
Bạn có thể cài đặt và tích hợp ApexQuery Plan vào SQL Server Management Studio, vì vậy các kế hoạch thực hiện có thể được xem trực tiếp từ SSMS.
Xem các kế hoạch thực hiện dự kiến trong ApexQuery Plan
Xem các kế hoạch thực hiện thực tế trong ApexSQL Plan
Để xem kế hoạch thực hiện thực tế của một truy vấn, hãy tiếp tục từ bước thứ 2 được đề cập trước đó, nhưng bây giờ, khi kế hoạch Ước tính được hiển thị, hãy nhấp vào nút Act Actual từ thanh ruy băng chính trong ApexQuery Plan.
Sau khi nhấp vào nút Thực tế của Cấm, kế hoạch thực hiện thực tế sẽ được hiển thị với bản xem trước chi tiết của các tham số chi phí cùng với dữ liệu kế hoạch thực hiện khác.
Thông tin thêm về xem kế hoạch thực hiện có thể được tìm thấy bằng cách theo liên kết này .
Công cụ yêu thích của tôi để có được và phân tích sâu các kế hoạch thực hiện truy vấn là SQL Sentry Plan Explorer . Nó thân thiện với người dùng, thuận tiện và toàn diện hơn cho việc phân tích chi tiết và trực quan hóa các kế hoạch thực hiện so với SSMS.
Dưới đây là một ảnh chụp màn hình mẫu để bạn có ý tưởng về chức năng nào được cung cấp bởi công cụ:
Đây chỉ là một trong những khung nhìn có sẵn trong công cụ. Lưu ý một tập hợp các tab ở dưới cùng của cửa sổ ứng dụng, cho phép bạn nhận được các loại khác nhau của biểu diễn kế hoạch thực hiện và thông tin bổ sung hữu ích.
Ngoài ra, tôi đã không nhận thấy bất kỳ giới hạn nào của phiên bản miễn phí của nó ngăn chặn việc sử dụng nó hàng ngày hoặc buộc bạn phải mua phiên bản Pro. Vì vậy, nếu bạn thích gắn bó với phiên bản miễn phí, không có gì cấm bạn làm như vậy.
CẬP NHẬT: (Cảm ơn Martin Smith ) Plan Explorer hiện miễn phí! Xem http://www.sqlsentry.com/products/plan-explorer/sql-server-query-view để biết chi tiết.
Speaking of third-party tools
khi không ai đề cập đến các công cụ của bên thứ ba.
Các kế hoạch truy vấn có thể được lấy từ phiên Sự kiện mở rộng thông qua query_post_execution_showplan
sự kiện. Đây là một phiên XEvent mẫu:
/*
Generated via "Query Detail Tracking" template.
*/
CREATE EVENT SESSION [GetExecutionPlan] ON SERVER
ADD EVENT sqlserver.query_post_execution_showplan(
ACTION(package0.event_sequence,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)),
/* Remove any of the following events (or include additional events) as desired. */
ADD EVENT sqlserver.error_reported(
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.module_end(SET collect_statement=(1)
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.rpc_completed(
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sp_statement_completed(SET collect_object_name=(1)
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sql_batch_completed(
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sql_statement_completed(
ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0))))
ADD TARGET package0.ring_buffer
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)
GO
Sau khi bạn tạo phiên, (trong SSMS), hãy vào Object Explorer và đi sâu vào Quản lý | Sự kiện mở rộng | Phiên. Nhấp chuột phải vào phiên "GetExecutPlan" và khởi động nó. Nhấp chuột phải vào nó một lần nữa và chọn "Xem dữ liệu trực tiếp".
Tiếp theo, mở một cửa sổ truy vấn mới và chạy một hoặc nhiều truy vấn. Đây là một cho AdventureWorks:
USE AdventureWorks;
GO
SELECT p.Name AS ProductName,
NonDiscountSales = (OrderQty * UnitPrice),
Discounts = ((OrderQty * UnitPrice) * UnitPriceDiscount)
FROM Production.Product AS p
INNER JOIN Sales.SalesOrderDetail AS sod
ON p.ProductID = sod.ProductID
ORDER BY ProductName DESC;
GO
Sau một hoặc hai phút, bạn sẽ thấy một số kết quả trong tab "GetExecutPlan: Live Data". Nhấp vào một trong các sự kiện query_post_execut_showplan trong lưới và sau đó nhấp vào tab "Kế hoạch truy vấn" bên dưới lưới. Nó sẽ trông giống như thế này:
EDIT : Mã XEvent và ảnh chụp màn hình được tạo từ SQL / SSMS 2012 w / SP2. Nếu bạn đang sử dụng SQL 2008 / R2, bạn có thể điều chỉnh tập lệnh để chạy tập lệnh. Nhưng phiên bản đó không có GUI, vì vậy bạn phải trích xuất XML showplan, lưu nó dưới dạng tệp * .sqlplan và mở nó trong SSMS. Đó là cồng kềnh. XE không tồn tại trong SQL 2005 hoặc sớm hơn. Vì vậy, nếu bạn không tham gia SQL 2012 trở lên, tôi thực sự muốn đề xuất một trong những câu trả lời khác được đăng ở đây.
Bắt đầu từ SQL Server 2016+, tính năng Store Store đã được giới thiệu để theo dõi hiệu suất. Nó cung cấp cái nhìn sâu sắc về lựa chọn kế hoạch truy vấn và hiệu suất. Nó không phải là sự thay thế hoàn toàn của dấu vết hoặc các sự kiện mở rộng, nhưng khi nó phát triển từ phiên bản này sang phiên bản khác, chúng tôi có thể có được một cửa hàng truy vấn đầy đủ chức năng trong các bản phát hành trong tương lai từ SQL Server. Luồng chính của Kho lưu trữ truy vấn
Kích hoạt Cửa hàng Truy vấn : Cửa hàng Truy vấn hoạt động ở cấp cơ sở dữ liệu trên máy chủ.
tempdb
cơ sở dữ liệu.
sys.database_query_store_options
(Giao dịch-SQL)
Thu thập thông tin trong Cửa hàng truy vấn : Chúng tôi thu thập tất cả thông tin có sẵn từ ba cửa hàng bằng cách sử dụng DMV của Cửa hàng truy vấn (Chế độ xem quản lý dữ liệu).
Lưu trữ kế hoạch truy vấn: Duy trì thông tin kế hoạch thực hiện và có thể chịu trách nhiệm cho việc nắm bắt tất cả thông tin có liên quan đến việc biên dịch truy vấn.
sys.query_store_query
(Transact-SQL)sys.query_store_plan
(Transact-SQL)sys.query_store_query_text
(Transact-SQL)
Cửa hàng thống kê thời gian chạy: Duy trì thông tin thống kê thực hiện và có lẽ đây là cửa hàng được cập nhật thường xuyên nhất. Những thống kê này đại diện cho dữ liệu thực hiện truy vấn.
sys.query_store_runtime_stats
(Giao dịch-SQL)
Truy vấn thống kê cửa hàng thống kê: Duy trì và nắm bắt thông tin thống kê chờ.
sys.query_store_wait_stats
(Giao dịch-SQL)
LƯU Ý: Kho lưu trữ thống kê truy vấn chỉ khả dụng trong SQL Server 2017+
Giống như với SQL Server Management Studio (đã được giải thích), Datagrip cũng có thể được giải thích ở đây .
- Bấm chuột phải vào một câu lệnh SQL và chọn Giải thích kế hoạch.
- Trong ngăn đầu ra, bấm Plan.
- Theo mặc định, bạn thấy biểu diễn cây của truy vấn. Để xem gói truy vấn, nhấp vào biểu tượng Hiển thị trực quan hoặc nhấn Ctrl + Shift + Alt + U
Đây là một điều quan trọng cần biết ngoài những điều đã nói trước đây.
Các kế hoạch truy vấn thường quá phức tạp để được biểu diễn bằng loại cột XML dựng sẵn có giới hạn 127 cấp độ của các phần tử lồng nhau. Đó là một trong những lý do tại sao sys.dm_exec_query_plan có thể quay lại NULL
hoặc thậm chí gây ra lỗi trong các phiên bản MS SQL trước đó, vì vậy nói chung sẽ an toàn hơn khi sử dụng sys.dm_execigin_query_plan . Loại thứ hai cũng có một tính năng thưởng hữu ích là chọn gói cho một tuyên bố cụ thể thay vì toàn bộ lô. Đây là cách bạn sử dụng nó để xem các gói cho các báo cáo hiện đang chạy:
SELECT p.query_plan
FROM sys.dm_exec_requests AS r
OUTER APPLY sys.dm_exec_text_query_plan(
r.plan_handle,
r.statement_start_offset,
r.statement_end_offset) AS p
Tuy nhiên, cột văn bản trong bảng kết quả không tiện dụng lắm so với cột XML. Để có thể nhấp vào kết quả sẽ được mở trong một tab riêng dưới dạng sơ đồ, mà không phải lưu nội dung của nó vào tệp, bạn có thể sử dụng một mẹo nhỏ (hãy nhớ rằng bạn không thể chỉ sử dụng CAST(... AS XML)
), mặc dù điều này sẽ chỉ hoạt động cho một hàng đơn:
SELECT Tag = 1, Parent = NULL, [ShowPlanXML!1!!XMLTEXT] = query_plan
FROM sys.dm_exec_text_query_plan(
-- set these variables or copy values
-- from the results of the above query
@plan_handle,
@statement_start_offset,
@statement_end_offset)
FOR XML EXPLICIT
Như tôi đã giải thích trong bài viết này , có hai loại kế hoạch thực hiện mà bạn có thể nhận được khi sử dụng SQL Server.
Kế hoạch thực hiện ước tính được tạo bởi Trình tối ưu hóa mà không chạy truy vấn SQL.
Để có được kế hoạch thực hiện ước tính, bạn cần kích hoạt SHOWPLAN_ALL
cài đặt trước khi thực hiện truy vấn.
THIẾT LẬP SHOWPLAN_ALL TRÊN
Bây giờ, khi thực hiện truy vấn SQL sau:
SELECT p.id
FROM post p
WHERE EXISTS (
SELECT 1
FROM post_comment pc
WHERE
pc.post_id = p.id AND
pc.review = 'Bingo'
)
ORDER BY p.title
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY
SQL Server sẽ tạo kế hoạch thực hiện ước tính sau:
| NodeId | Parent | LogicalOp | EstimateRows | EstimateIO | EstimateCPU | AvgRowSize | TotalSubtreeCost | EstimateExecutions |
|--------|--------|----------------------|--------------|-------------|-------------|------------|------------------|--------------------|
| 1 | 0 | NULL | 10 | NULL | NULL | NULL | 0.03374284 | NULL |
| 2 | 1 | Top | 10 | 0 | 3.00E-06 | 15 | 0.03374284 | 1 |
| 4 | 2 | Distinct Sort | 30 | 0.01126126 | 0.000504114 | 146 | 0.03373984 | 1 |
| 5 | 4 | Inner Join | 46.698 | 0 | 0.00017974 | 146 | 0.02197446 | 1 |
| 6 | 5 | Clustered Index Scan | 43 | 0.004606482 | 0.0007543 | 31 | 0.005360782 | 1 |
| 7 | 5 | Clustered Index Seek | 1 | 0.003125 | 0.0001581 | 146 | 0.0161733 | 43 |
Sau khi chạy truy vấn, chúng tôi quan tâm đến việc nhận kế hoạch thực hiện ước tính, bạn cần phải vô hiệu hóa SHOWPLAN_ALL
, nếu không, phiên cơ sở dữ liệu hiện tại sẽ chỉ tạo kế hoạch thực hiện ước tính thay vì thực hiện các truy vấn SQL được cung cấp.
SET SHOWPLAN_ALL OFF
Trong ứng dụng SQL Server Management Studio, bạn có thể dễ dàng nhận được kế hoạch thực hiện ước tính cho bất kỳ truy vấn SQL nào bằng cách nhấn CTRL+L
phím tắt.
Kế hoạch thực thi SQL thực tế được Trình tối ưu hóa tạo ra khi chạy truy vấn SQL. Nếu thống kê bảng cơ sở dữ liệu là chính xác, kế hoạch thực tế sẽ không khác biệt đáng kể so với kế hoạch ước tính.
Để có được kế hoạch thực hiện thực tế trên SQL Server, bạn cần kích hoạt các STATISTICS IO, TIME, PROFILE
cài đặt, như được minh họa bằng lệnh SQL sau:
SET STATISTICS IO, TIME, PROFILE ON
Bây giờ, khi chạy truy vấn trước đó, SQL Server sẽ tạo kế hoạch thực hiện sau:
| Rows | Executes | NodeId | Parent | LogicalOp | EstimateRows | EstimateIO | EstimateCPU | AvgRowSize | TotalSubtreeCost |
|------|----------|--------|--------|----------------------|--------------|-------------|-------------|------------|------------------|
| 10 | 1 | 1 | 0 | NULL | 10 | NULL | NULL | NULL | 0.03338978 |
| 10 | 1 | 2 | 1 | Top | 1.00E+01 | 0 | 3.00E-06 | 15 | 0.03338978 |
| 30 | 1 | 4 | 2 | Distinct Sort | 30 | 0.01126126 | 0.000478783 | 146 | 0.03338679 |
| 41 | 1 | 5 | 4 | Inner Join | 44.362 | 0 | 0.00017138 | 146 | 0.02164674 |
| 41 | 1 | 6 | 5 | Clustered Index Scan | 41 | 0.004606482 | 0.0007521 | 31 | 0.005358581 |
| 41 | 41 | 7 | 5 | Clustered Index Seek | 1 | 0.003125 | 0.0001581 | 146 | 0.0158571 |
SQL Server parse and compile time:
CPU time = 8 ms, elapsed time = 8 ms.
(10 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'post'. Scan count 0, logical reads 116, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'post_comment'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(6 row(s) affected)
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 1 ms.
Sau khi chạy truy vấn, chúng tôi quan tâm đến việc nhận kế hoạch thực hiện thực tế, bạn cần phải tắt các STATISTICS IO, TIME, PROFILE ON
cài đặt như thế này:
SET STATISTICS IO, TIME, PROFILE OFF
Trong ứng dụng SQL Server Management Studio, bạn có thể dễ dàng nhận được kế hoạch thực hiện ước tính cho bất kỳ truy vấn SQL nào bằng cách nhấn CTRL+M
phím tắt.
Để biết thêm chi tiết về cách nhận kế hoạch thực hiện khi sử dụng SQL Server, hãy xem bài viết này .
Bạn cũng có thể thực hiện điều đó thông qua powershell bằng cách sử dụng SET STATISTICS XML ON để có được kế hoạch thực tế. Tôi đã viết nó để nó hợp nhất các kế hoạch đa tuyên bố thành một kế hoạch;
########## BEGIN : SCRIPT VARIABLES #####################
[string]$server = '.\MySQLServer'
[string]$database = 'MyDatabase'
[string]$sqlCommand = 'EXEC sp_ExampleSproc'
[string]$XMLOutputFileName = 'sp_ExampleSproc'
[string]$XMLOutputPath = 'C:\SQLDumps\ActualPlans\'
########## END : SCRIPT VARIABLES #####################
#Set up connection
$connectionString = "Persist Security Info=False;Integrated Security=true;Connection Timeout=0;Initial Catalog=$database;Server=$server"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
#Set up commands
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$command.CommandTimeout = 0
$commandXMLActPlanOn = new-object system.data.sqlclient.sqlcommand("SET STATISTICS XML ON",$connection)
$commandXMLActPlanOff = new-object system.data.sqlclient.sqlcommand("SET STATISTICS XML OFF",$connection)
$connection.Open()
#Enable session XML plan
$result = $commandXMLActPlanOn.ExecuteNonQuery()
#Execute SP and return resultsets into a dataset
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
#Set up output file name and path
[string]$fileNameDateStamp = get-date -f yyyyMMdd_HHmmss
[string]$XMLOutputFilePath = "$XMLOutputPath$XMLOutputFileName`_$fileNameDateStamp.sqlplan"
#Pull XML plans out of dataset and merge into one multi-statement plan
[int]$cntr = 1
ForEach($table in $dataset.Tables)
{
if($table.Columns[0].ColumnName -eq "Microsoft SQL Server 2005 XML Showplan")
{
[string]$fullXMLPlan = $Table.rows[0]."Microsoft SQL Server 2005 XML Showplan"
if($cntr -eq 1)
{
[regex]$rx = "\<ShowPlanXML xmlns\=.{1,}\<Statements\>"
[string]$startXMLPlan = $rx.Match($fullXMLPlan).Value
[regex]$rx = "\<\/Statements\>.{1,}\<\/ShowPlanXML\>"
[string]$endXMLPlan = $rx.Match($fullXMLPlan).Value
$startXMLPlan | out-file -Append -FilePath $XMLOutputFilePath
}
[regex]$rx = "\<StmtSimple.{1,}\<\/StmtSimple\>"
[string]$bodyXMLPlan = $rx.Match($fullXMLPlan).Value
$bodyXMLPlan | out-file -Append -FilePath $XMLOutputFilePath
$cntr += 1
}
}
$endXMLPlan | out-file -Append -FilePath $XMLOutputFilePath
#Disable session XML plan
$result = $commandXMLActPlanOff.ExecuteNonQuery()
$connection.Close()
Giải thích kế hoạch thực hiện có thể rất chi tiết và chiếm khá nhiều thời gian đọc, nhưng tóm lại nếu bạn sử dụng 'giải thích' trước truy vấn, nó sẽ cung cấp cho bạn rất nhiều thông tin bao gồm cả phần nào được thực hiện trước và vì vậy. Nếu bạn muốn đọc thêm một chút chi tiết về điều này, tôi đã biên soạn một blog nhỏ về điều này, điều này cũng chỉ cho bạn những người giới thiệu phù hợp. https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c470