SQL Server 使用 OPTION (RECOMPILE) 和查询存储的查询

设置
        我们正在使用 WideWorldImporters 数据库,您可以从 Github 下载【sql-server-samples/samples/databases/wide-world-importers at master · microsoft/sql-server-samples · GitHub】。我正在运行SQL Server 2017 的最新 CU【https://sqlserverbuilds.blogspot.com/】,但这适用于任何版本的查询存储(SQL Server 2016 及更高版本)和 Azure SQL 数据库。下面的代码将启用查询存储,将 QUERY_CAPTURE_MODE 设置为 ALL(要了解各种不同以及建议用于生产的内容,请查看我的查询存储设置帖子【https://blog.csdn.net/hefeng_aspnet/article/details/140130527】),然后清除查询存储中的所有内容。我通常不建议您清除查询存储,但我们正在恢复演示数据库,这是一个演示,所以我要确保我们从头开始。最后,我们将创建一个用于测试的存储过程,该存储过程使用 RECOMPILE 创建,然后完全释放过程缓存。请注意,我不建议向存储过程添加 RECOMPILE 选项 - 这意味着每次执行时都会重新编译整个存储过程。我也不建议在生产中释放过程缓存 - 这只是为了演示目的。
USE [master];
GO
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE = ON;
GO
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE (OPERATION_MODE = READ_WRITE, QUERY_CAPTURE_MODE = ALL);
GO
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR;
GO
 
DROP PROCEDURE IF EXISTS Sales.usp_GetOrderInfo 
GO
 
CREATE PROCEDURE Sales.usp_GetOrderInfo
(@OrderID INT)
WITH RECOMPILE
AS
BEGIN
SELECT
o.OrderID,
o.CustomerID,
o.OrderDate,
ol.Quantity,
ol.UnitPrice
FROM Sales.Orders o
JOIN Sales.OrderLines ol
ON o.OrderID = ol.OrderID
WHERE o.OrderID = @OrderID;
END
GO
 
DBCC FREEPROCCACHE;
GO

测试
        首先,执行一个临时查询(不属于存储过程的一部分,具有 OPTION (RECOMIPLE) 提示):

SELECT
i.InvoiceID,
i.CustomerID,
i.InvoiceDate,
il.Quantity,
il.UnitPrice
FROM Sales.Invoices i
JOIN Sales.InvoiceLines il
ON i.InvoiceID = il.InvoiceID
WHERE i.InvoiceID = 54983
OPTION (RECOMPILE);
GO 10

如果我们检查计划缓存,您会注意到没有证据表明该查询已执行:

SELECT
qs.execution_count,
st.text, 
qs.creation_time
FROM sys.dm_exec_query_stats AS [qs] 
CROSS APPLY sys.dm_exec_sql_text ([sql_handle]) [st]
CROSS APPLY sys.dm_exec_query_plan ([plan_handle]) [p]
WHERE [st].[text][/text] LIKE '%Sales.Invoices%';
GO

但如果我们查看查询存储,我们确实会看到以下查询:
SELECT
[qsq].[query_id], 
[qsp].[plan_id],
[qsq].[object_id],
[rs].[count_executions],
[rs].[last_execution_time],
[rs].[avg_duration],
[rs].[avg_logical_io_reads],
[qst].[query_sql_text],
TRY_CONVERT(XML, [qsp].[query_plan]) AS [QueryPlan_XML],
[qsp].[query_plan] 
FROM [sys].[query_store_query] [qsq] 
JOIN [sys].[query_store_query_text] [qst]
ON [qsq].[query_text_id] = [qst].[query_text_id]
JOIN [sys].[query_store_plan] [qsp] 
ON [qsq].[query_id] = [qsp].[query_id]
JOIN [sys].[query_store_runtime_stats] [rs] 
ON [qsp].[plan_id] = [rs].[plan_id]
WHERE [qst].[query_sql_text] LIKE '%Sales.Invoices%';
GO 

如果我们展开 query_sql_text 列(由于空间原因删除了中间的文本),你会看到文本包含OPTION (RECOMPILE)。这很酷。

现在让我们执行使用 RECOMPILE 创建的存储过程,然后检查计划缓存:

EXEC Sales.usp_GetOrderInfo 57302;
GO 10
 
SELECT
qs.execution_count,
st.text, 
qs.creation_time
FROM sys.dm_exec_query_stats AS [qs] 
CROSS APPLY sys.dm_exec_sql_text ([sql_handle]) [st]
CROSS APPLY sys.dm_exec_query_plan ([plan_handle]) [p]
WHERE [st].[text][/text] LIKE '%Sales.Orders%';
GO

当我们检查查询存储时,我们确实看到了查询: 

SELECT
[qsq].[query_id], 
[qsp].[plan_id],
[qsq].[object_id],
OBJECT_NAME([qsq].[object_id]) AS ObjectName,
[rs].[count_executions],
[rs].[last_execution_time],
[rs].[avg_duration],
[rs].[avg_logical_io_reads],
[qst].[query_sql_text],
TRY_CONVERT(XML, [qsp].[query_plan]) AS [QueryPlan_XML],
[qsp].[query_plan] /* nvarchar(max) */
FROM [sys].[query_store_query] [qsq] 
JOIN [sys].[query_store_query_text] [qst]
ON [qsq].[query_text_id] = [qst].[query_text_id]
JOIN [sys].[query_store_plan] [qsp] 
ON [qsq].[query_id] = [qsp].[query_id]
JOIN [sys].[query_store_runtime_stats] [rs] 
ON [qsp].[plan_id] = [rs].[plan_id]
WHERE OBJECT_NAME([qsq].[object_id]) = 'usp_GetOrderInfo';
GO

概括
        无论在何处使用 OPTION(RECOMPILE)——在临时查询的语句级别还是在存储过程内的语句——以及在创建或执行期间在过程级别使用 RECOMPILE 选项时——查询文本、计划和执行统计信息仍会在查询存储中捕获。

参考:Queries with OPTION (RECOMPILE) and Query Store - Erin Stellato 

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值