我们在做SqlServer的查询调优的时候,经常会在语句末尾用到option(loop/merge/hash join)或在join语句前直接声明loop/merge/hash,来强制SqlServer使用某一特定类型的join方式。但是有些时候经过查询优化器优化后的执行计划可能会和你声明的join方式产生冲突,导致执行计划生成失败,我们来看一下下面这个典型案例。

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 的提示符(Option/With等提示符)不是什么时候都可以用的的更多相关文章

  1. 02_Linux基础-文件系统层次结构-提示符-进程-命令格式-隐藏文件-通配符-绝对相对路径-{1..100}-ls-mkdir-其他基础命令

    02_Linux基础-ls-mkdir-cd-pwd-man-useradd-su-rm-tree-tab-passwd-w-ssh-touch-date-stat-cp-mv-du-文件系统层次结构 ...

  2. 11 自定制shell提示符

    shell提示符  huiubantu@ubuntu:~$ shell提示符保存在PS1变量中 包括用户名,主机名,当前工作目录 可以通过echo命令查看PS1的内容 huiubantu@ubuntu ...

  3. MySQL学习笔记(2) - 修改MySQL提示符的两种方法

    学习于慕课网 http://www.imooc.com/video/1806 1.方法一: cmd中处于未登录状态时,输入 mysql -uroot -p自己的密码 --prompt 新的提示符 示例 ...

  4. Bash提示符

    Bash有四种提示符 1.基本提示符(PS1):即$符号,是默认的基本提示符,当Shell运行在交互模式下时,该提示符会出现在屏幕上,可以设置为其它符号. 显示PS1设置[cb@cb:16:36:23 ...

  5. 修改cmd窗口mysql的提示符:

    mysql提示符: \D  完整的日期 \d   当前数据库 \h    服务器地址 \u    当前用户 登录数据库的时候设置提示符:  mysql  -uroot  -proot  --promp ...

  6. MySQL修改提示符

    MySQL提示符 \D 完整日期 \d 当前数据库 \h 服务器名称 \u 当前用户 1.连接之前修改提示符 mysql -uroot -proot --prompt [MySQL提示符] 2.连接之 ...

  7. Linux中的提示符

    root的提示符:# 一般用户的提示符:$

  8. 安装SQL Servre2000时提示“command line option syntax error! type command /? for help”

    问题: 当程序正在安装ms数据访问组件时,弹出错误提示框:command line option syntax error,type command/? for help,点击确定继续:到了程序正在安 ...

  9. B-Tree索引在sqlserver和mysql中的应用

    在谈论数据库性能优化的时候,通常都会提到“索引”,但很多人其实并没有真正理解索引,也没有搞清楚索引为什么就能加快检索速度,以至于在实践中并不能很好的应用索引.事实上,索引是一种廉价而且十分有效的优化手 ...

随机推荐

  1. 长城坑爹宽带,劫持用户DNS赚取购物返利

    今天回来登录www.jd.com 打算淘点东西,登录后发现地址栏跳到 http://www.jd.com/?utm_source=click.linktech.cn&utm_medium=tu ...

  2. 删除Checkout with Multiple Addresses

    如果选择No,您的客户在结账时只可以输入一个收货地址,订单的货物都会送到这个地址.如果您选择Yes,您的客户将可以选择发货到多个地址,在购物车中的Proceed to Checkout按钮下面将会出现 ...

  3. 【转】【翻】Android Design Support Library 的 代码实验——几行代码,让你的 APP 变得花俏

    转自:http://mrfufufu.github.io/android/2015/07/01/Codelab_Android_Design_Support_Library.html [翻]Andro ...

  4. 【转】ViewPager实现一个页面多个Item的显示

    转自:http://billyyuan.iteye.com/blog/1941538 ViewPager实现一个页面多个Item的显示 博客分类: android   代码在: https://cod ...

  5. XLST

    xlst转换 // 读入源请求和mapping配置 StreamSource xmlSource = new StreamSource(new InputStreamReader(new ByteAr ...

  6. 异步刷新tableView

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self.tableView rel ...

  7. iOS:runtime最全的知识总结

    runtime 完整总结 好东西,应该拿出来与大家分享... 南峰子博客地址:http://southpeak.github.io/blog/categories/ios/ 原文链接:http://w ...

  8. RedHat6.6更新Centos6yum源

    RedHat6.6更新Centos6yum源 一.    删除自带的RedHat6.6yum源 1-       rpm -qa|grep yum|xargs rpm -e --nodeps(不检查依 ...

  9. nginx端口被占用解决方案

    killall -9 nginx或service nginx restart(重新启动)

  10. Android适配(屏幕适配、国际化适配)-转

    首先来说一下Android的屏幕适配: 关于Android屏幕的一些基本概念知识,自行充电..在此只介绍实际开发过程中的使用 1.说到Android的屏幕适配,首当其冲的就是图片的适配 图片适配遵循两 ...