Sql server SQL Server-不使用别名创建计划指南

Sql server SQL Server-不使用别名创建计划指南,sql-server,sql-server-2012,Sql Server,Sql Server 2012,我正在尝试在SQL Server 2012 SP3 Enterprise Edition中为应用程序运行的特定查询创建计划指南,这意味着我无法以任何方式更改查询 查询如下所示: (@P1 nvarchar(5),@P2 bigint) DELETE FROM INVENTSUMDELTA WHERE ((DATAAREAID=@P1) AND (TTSID=@P2)) 为了创建计划指南,我使用了以下查询: EXEC sp_create_plan_guide @name = N'INVEN

我正在尝试在SQL Server 2012 SP3 Enterprise Edition中为应用程序运行的特定查询创建计划指南,这意味着我无法以任何方式更改查询

查询如下所示:

(@P1 nvarchar(5),@P2 bigint)
DELETE FROM INVENTSUMDELTA WHERE ((DATAAREAID=@P1) AND (TTSID=@P2))
为了创建计划指南,我使用了以下查询:

EXEC sp_create_plan_guide   
@name = N'INVENTSUMDELTAINDEX', 
@stmt = N'DELETE FROM INVENTSUMDELTA WHERE ((DATAAREAID=@P1) AND (TTSID=@P2))',    
@type = N'SQL',  
@module_or_batch = NULL,  
@params = N'@P1 nvarchar(5),@P2 bigint',  
@hints = N'OPTION (TABLE HINT ( INVENTSUMDELTA, INDEX( I_2397TTSDIMIDX )))';
但是,我收到了一个错误:

味精8724,16级,状态1,第1行 无法执行查询。无法在Table HINT子句中指定表值函数或OPENROWSET函数“INVENTSUMDELTA”

我检查了文档,发现以下内容:

表提示(公开的\u对象\u名称[,[,]…n]] 将指定的表提示应用于与公开的\u对象\u名称相对应的表或视图。[……]

公开的\u对象\u名称可以是以下引用之一:

  • 当查询的FROM子句中的表或视图使用别名时,exposed_object_name就是别名

  • 未使用别名时,exposed_object_name与FROM子句中引用的表或视图完全匹配。例如,如果使用由两部分组成的名称引用表或视图,则公开的对象名称与由两部分组成的名称相同

由此我推断,应该可以为不使用别名的查询创建计划指南。然而,我无法让它工作


因此,我的问题是:如何在不使用别名和不更改原始查询的情况下创建计划指南?

错误消息具有误导性。它与对象的性质无关(对于不存在的对象,您将得到相同的错误)。问题是它不适用于
DELETE
语句——任何
TABLE HINT
引用作为
DELETE
目标的表都会产生此错误。这也不限于计划指南——带有选项的普通
DELETE
也将失败:

DELETE FROM does_not_exist 
OPTION (TABLE HINT (does_not_exist, INDEX (does_not_exist)))
无法执行查询。不能在Table HINT子句中指定表值函数或OPENROWSET函数“不存在”

这似乎是一个错误,因为如果语句在表和查询级别都添加了
with(ROWLOCK)
提示,那么错误就会消失:

DELETE FROM does_not_exist WITH (ROWLOCK)
OPTION (TABLE HINT (does_not_exist, ROWLOCK, INDEX (does_not_exist)))
无效的对象名称“不存在”

中也讨论了同样的问题,解决方案是以允许应用提示的形式重写查询

在这种情况下,我们不能直接重写查询,但我们仍然可以通过使用:


与往常一样,如果没有其他帮助(更新统计数据、创建新索引、删除次优索引),计划指南应该是最后的手段。此答案假设您已经查看了所有其他选项,并且计划指南是必需的。

有一个表(在dbo架构中),但没有UDF。感谢您的回答!我认为这与删除缺少一个适当的FROM子句有关,但没有想到这个解决方法。我下周才能尝试该解决方案,因此将等待并将其标记为已接受。@Monzie:我已验证该解决方案是否有效(通过创建第二个索引并在打开和关闭“计划指南”的情况下比较语句之间的执行计划),因此,如果该解决方案在您的情况下不起作用,请务必添加详细信息。特别是,在计划指南中匹配查询文本和参数化可能很棘手。@Monzie:还有一件事——我不确定执行计划是否通过传入的参数反映行估计。如果是这样,则可能需要在执行时传入代表性参数值(在回滚以防止实际删除行的事务中!),或者使用
OPTIMIZE FOR
提示提供代表性值。这是使用固定查询计划的负面后果,而不是只使用提示的指南。请注意,
单独优化
可能会启用索引的使用,从而使整个固定查询变得不必要。太好了!这很有效。此查询来自Dynamics AX,它需要大量索引提示。感谢您的出色解决方案。毕竟,《计划指南》的整个要点是指导SQL在无法修改第三方查询时如何执行它们。
-- Alternate query using hint.
DECLARE @sql NVARCHAR(MAX) = N'WITH T AS (
    SELECT * 
    FROM INVENTSUMDELTA WITH (INDEX (I_2397TTSDIMIDX))
    WHERE ((DATAAREAID=@P1) AND (TTSID=@P2))
)
DELETE T';
DECLARE @params NVARCHAR(MAX) = N'@P1 nvarchar(5),@P2 bigint'

-- Put the execution plan in the cache.
EXEC sp_executesql @sql, @params = @params, @P1=NULL, @P2=NULL;

-- Retrieve it.
DECLARE @query_plan NVARCHAR(MAX);
SELECT @query_plan = query_plan  
FROM sys.dm_exec_query_stats AS qs   
CROSS APPLY sys.dm_exec_sql_text(qs.[sql_handle]) AS st  
CROSS APPLY sys.dm_exec_text_query_plan(qs.[plan_handle], DEFAULT, DEFAULT) AS qp  
WHERE st.[text] LIKE '(' + @params + ')%' + @sql;

-- Create a plan guide associating the query with the new execution plan.
EXEC sp_create_plan_guide   
    @name = N'INVENTSUMDELTAINDEX', 
    @stmt = N'DELETE FROM INVENTSUMDELTA WHERE ((DATAAREAID=@P1) AND (TTSID=@P2))',    
    @type = N'SQL',  
    @module_or_batch = NULL,  
    @params = @params,
    @hints = @query_plan;