Rob*_*son 4 sql t-sql sql-server stored-procedures
在回答这个问题时,KM说
如果您在SQL Server 2005之上或之上,您可以使用IF在同一过程中拥有多个查询,并且每个查询都会为其保存一个查询计划(相当于旧版本中的每个查询计划),请参阅我的答案中的文章或链接到适当的部分:sommarskog.se/dyn-search-2005.html#IF
HLGEM补充道
您也可以在早期版本的SQL Server中执行此操作.
我读了Sommarskog的优秀文章,但没有看到任何有关多个计划的内容.
在以后的研究中,我读报价这里自Gert德雷珀斯:
因为SQL Server每个存储过程只允许一个执行计划...
我不知道原始文章的日期或他所指的SQL Server版本.
有没有人有一个可靠的参考资料来讨论这个,或者更好的是,一个证明这是真的测试?
我还有一步补充,应该让一切都更清晰.生成计划信息后,运行以下语句(使用正确的计划句柄)以查看ShowPlan XML.
DECLARE @val as VARBINARY(64)
-- NOTE: Replace the Hex string with the current plan_handle !
SET @val = CONVERT(VARBINARY(64), 0x05001300045A3D02B801BE11000000000000000000000000)
SELECT * FROM sys.dm_exec_query_plan(@val)
Run Code Online (Sandbox Code Playgroud)
查看生成的XML显示有2个QueryPlan元素,2个或更多StmtSimple/StmtCond元素,并且总体上只有1个Batch.正如gbn所提到的那样,"执行计划"和"查询计划"之间存在差异.这似乎清楚地说明了我们在所有sys.dm_查询中实际查看的部分.
SQLDN上的sys.dm_exec_query_stats,SQL 2008
SQLDN上的sys.dm_exec_query_plan,SQL 2008
因此,所有这些信息,返回的plan_handle是执行计划; 部分是查询计划项目.
-
在Andrew的评论之后,我重新测试了,确实查询计划处理是一样的.而且,只是为了确定 - 我创建了存储过程的副本,只更改了名称,并针对该存储过程重新进行了测试.这也导致生成一组新的查询部分,这些部分共享相同的计划句柄.
所以,gbn的回答似乎是正确的,至少我在这里测试过.有趣的东西.
-
Gert Drapers的后者引用似乎是假的 - 这是我的考验.我在这里使用SQL 2005.在我的测试中,我看到为同一存储过程的不同部分生成了2个查询计划.
首先,我创建了两个表,tblTag1和tblTagWithGUID.我使它们有点类似,以便我的存储过程可以在表和返回结果之间交替使用相同的结果表布局.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
-- Table #1, tblTag1
CREATE TABLE [dbo].[tblTag1](
[id] [int] IDENTITY(1,1) NOT NULL,
[createDate] [datetime] NOT NULL CONSTRAINT [DF_tblTag1_createDate] DEFAULT (getdate()),
[someTag] [varchar](100) NOT NULL,
CONSTRAINT [PK_tblTag1] 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]
GO
-- Table #2, tblTagWithGUID
CREATE TABLE [dbo].[tblTagWithGUID](
[id] [int] IDENTITY(1,1) NOT NULL,
[createDate] [datetime] NOT NULL CONSTRAINT [DF_tblTagWithGUID_createDate] DEFAULT (getdate()),
[someTag] [varchar](100) NOT NULL,
[someGUID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_tblTagWithGUID_someGUID] DEFAULT (newid()),
CONSTRAINT [PK_tblTagWithGUID] 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]
GO
Run Code Online (Sandbox Code Playgroud)
二,存储过程.在存储过程中,我根据参数从一个或另一个表中选择.
CREATE PROCEDURE spLoadTags
@Pick AS BIT = NULL
AS
BEGIN
IF @Pick = 0
SELECT id, createDate, someTag FROM tblTag1
IF @Pick = 1
SELECT id, createDate, someTag FROM tblTagWithGUID
END
Run Code Online (Sandbox Code Playgroud)
我在每个表中添加了一些数据 - 然后用0或1作为参数运行存储过程几十次.
接下来,我运行此查询以检查生成的查询计划.对不起,如果有人因为我的邋iness而感到冒犯 - 当然这不是生产代码.
WITH PlanData AS
(
SELECT
(SELECT SUBSTRING(text, statement_start_offset/2 + 1,
(CASE WHEN statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(MAX),text)) * 2
ELSE statement_end_offset
END - statement_start_offset)/2)
FROM sys.dm_exec_sql_text(sql_handle) WHERE [text] like '%SELECT id, createDate, someTag FROM tblTag%') AS query_text,
plan_handle
FROM sys.dm_exec_query_stats
)
SELECT
DISTINCT
execution_count,
PlanData.query_text,
sys.dm_exec_query_stats.plan_handle
FROM sys.dm_exec_query_stats, PlanData
WHERE
sys.dm_exec_query_stats.plan_handle = PlanData.plan_handle and
PlanData.query_text IS NOT NULL
ORDER BY execution_count DESC
Run Code Online (Sandbox Code Playgroud)
当我运行这个查询时,我看到了一堆计划,但因为我已经运行了几十次存储过程,所以不同的部分最终位于顶部.
execution_count query_text plan_handle
96 SELECT id, createDate, someTag FROM tblTag1 0x05001200045A3D02B8613E13000000000000000000000000
96 SELECT id, createDate, someTag FROM tblTagWithGUID 0x05001200045A3D02B8613E13000000000000000000000000
Run Code Online (Sandbox Code Playgroud)
我只包括这两行,但希望这很简单,其他人可以验证我的结果.如果您像我一样使用SQL管理工具,您可能会看到其他行; 可能是由浏览表格或其他活动引起的.
我们都是正确的:-)
"查询计划"在缓存中最多有2个条目:一个串行和一个并行
每个用户都有自己的"执行上下文"来运行计划
如果对象不合格,计划会有所不同
所以,您可能认为计划不是因为表没有使用模式限定(在SQL Server 2000,2005和2008中是相同的)
来自MSDN/BOL" 执行计划缓存和重用 "
编辑: