SqlServer 的提示符(Option/With等提示符)不是什么时候都可以用的
2016-08-23 19:14
483 查看
我们在做SqlServer的查询调优的时候,经常会在语句末尾用到option(loop/merge/hash join)或在join语句前直接声明loop/merge/hash,来强制SqlServer使用某一特定类型的join方式。但是有些时候经过查询优化器优化后的执行计划可能会和你声明的join方式产生冲突,导致执行计划生成失败,我们来看一下下面这个典型案例。
我们在上面的查询语句中使用了option提示符强制让SqlServer使用Hash Join来做join查询,在执行该语句时我们会得到如下错误信息:
消息 8622,级别 16,状态 1,第 3 行
由于此查询中定义了提示,查询处理器未能生成查询计划。请重新提交查询,并且不要在查询中指定任何提示,也不要使用 SET FORCEPLAN。
为什么SqlServer会产生这么一个信息呢?
主要是因为查询优化器在分析上面这个语句的时候发现了inner join的条件是
a.id=b.id
然后又在where条件中发现了
a.id=@id1 and b.id=@id2
那么在查询优化器看来,@id1和@id2可能为任何int类型的值,甚至有可能@id1=@id2,比如@id1=@id2=1
那么这个时候查询优化器会认为inner join完全是多余的,所以上面的语句就被查询优化器优化为了cross join的方式,如下方式,然后在这个结果上再做了a.id=1 and b.id=1的过滤
这个时候你去观察上面这个语句的查询计划,发现在Nested Loops有一个红色的小叉,表示这个join是没有Predicate的,也就是没有join条件的(Cross Join就没有条件),术语叫非equijoin,实际上下面这个执行计划中join两边的索引,只要有一边没有Predicate,那么该join都是非equijoin。
而非equijoin是不能使用Merge/Hash join的,换句话说cross join是不能用Merge/Hash join的,只能用Loop join,所以最上面的那条语句会报错,要求去掉option提示符。所以SqlServer的提示符不是什么时候都可以用的,甚至with(index(...))这种强制使用索引的提示符也不能随便乱用,因为执行计划中的某些步骤可能会和你声明的提示符产生冲突,从而导致执行计划生成失败而报错,要根据具体情况具体分析合理使用各种SqlServer的提示符。
declare @id1 int=1,@id2 int=1 select * from [dbo].[T_People] a inner join [dbo].[T_People_II] b on a.id=b.id where a.id=@id1 and b.id=@id2 option(hash join)
我们在上面的查询语句中使用了option提示符强制让SqlServer使用Hash Join来做join查询,在执行该语句时我们会得到如下错误信息:
消息 8622,级别 16,状态 1,第 3 行
由于此查询中定义了提示,查询处理器未能生成查询计划。请重新提交查询,并且不要在查询中指定任何提示,也不要使用 SET FORCEPLAN。
为什么SqlServer会产生这么一个信息呢?
主要是因为查询优化器在分析上面这个语句的时候发现了inner join的条件是
a.id=b.id
然后又在where条件中发现了
a.id=@id1 and b.id=@id2
那么在查询优化器看来,@id1和@id2可能为任何int类型的值,甚至有可能@id1=@id2,比如@id1=@id2=1
那么这个时候查询优化器会认为inner join完全是多余的,所以上面的语句就被查询优化器优化为了cross join的方式,如下方式,然后在这个结果上再做了a.id=1 and b.id=1的过滤
select * from [dbo].[T_Peopl] a cross join [dbo].[T_People_II] b
这个时候你去观察上面这个语句的查询计划,发现在Nested Loops有一个红色的小叉,表示这个join是没有Predicate的,也就是没有join条件的(Cross Join就没有条件),术语叫非equijoin,实际上下面这个执行计划中join两边的索引,只要有一边没有Predicate,那么该join都是非equijoin。
而非equijoin是不能使用Merge/Hash join的,换句话说cross join是不能用Merge/Hash join的,只能用Loop join,所以最上面的那条语句会报错,要求去掉option提示符。所以SqlServer的提示符不是什么时候都可以用的,甚至with(index(...))这种强制使用索引的提示符也不能随便乱用,因为执行计划中的某些步骤可能会和你声明的提示符产生冲突,从而导致执行计划生成失败而报错,要根据具体情况具体分析合理使用各种SqlServer的提示符。
相关文章推荐
- SQLserver不是可以识别的内置函数名称"的错误,通过set statistics time on能得到SQL语句的执行时间精确到毫秒.
- 不是什么时候都可以用栈来声明对象并使用(自动释放)——Delphi里到处都是编译器魔法,并且自动帮助实例化界面元素指针
- 解决SQL备份时,提示"不是多簇媒体集的一部分,可以使用BACKUP WITH FORMAT 来构造新的媒体集."
- 解决SQL备份时,提示"不是多簇媒体集的一部分,可以使用BACKUP WITH FORMAT 来构造新的媒体集."
- SQLserver不是可以识别的内置函数名称"的错误,通过set statistics time on能得到SQL语句的执行时间精确到毫秒.
- sqlserver-一次updlock和withnolock和with check option 的报错原因分析
- 一个不错的Options交易策略网"option trading tips"可以学到各种Options的定义.
- with check option(转载)
- 将不确定变为确定~SQLSERVER是否可以进行位运算?
- 继承自TWinControl的控件不能在设计期间接受子控件,用代码设置子控件却可以(它的自绘是直接改写PaintWindow虚函数,而不是覆盖Paint函数——对TWinControl.WMPaint又有新解了)
- Make Eclipse with Maven be your first Partener!(把eclipse里面的maven项目变成可以直接发布的web工程)
- error:C3881 assembly access specifiers are only available in code compiled with a /clr option
- 创建视图时with check option问题
- CSDN的排名什么时候才不是“千里之外”解决方法
- ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot exec
- js实现删除select下拉框对应option(旧版本,现版本可以直接jQuery显示或隐藏,兼容IE)
- Error Code: 1290. The MySQL server is running with the --secure-file-priv option
- ORA-39700: database must be opened with UPGRADE option
- 用SQLSERVER里的bcp命令或者bulkinsert命令也可以把dat文件导入数据表
- 转: 技术不是一切,可以作为兴趣