我们在做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. 完美解决 .txt文件在Mac上不能打开的问题

  2. DHT(Distributed Hash Table) Translator

    DHT(Distributed Hash Table) Translator What is DHT? DHT is the real core of how GlusterFS aggregates ...

  3. JVM培训作业第二周

    1. jre的运行时主要jar文件rt.jar都很大,这导致了用java做的桌面客户端程序很难发布绑定jre发布.这在很大程度上限制了java桌面软件 的分发.可是,jre并不是在所有的用户计算机上都 ...

  4. SQL Server 2012 新的分页函数 OFFSET & FETCH NEXT

    DECLARE @page INT, @size INT;select @page = 300, @size = 10 SELECT *FROM gpcomp1.GPCUSTWHERE company ...

  5. Linux系统产生随机数的3种方法

    Linux系统产生随机数的3种方法 方法一:生成8位随机数 [root@localhost ~]# echo "$RANDOM$(date +%N%t)" | md5sum | c ...

  6. 30天,O2O速成攻略【7.19深圳站】

    活动概况 时间:2015年07月19日13:30-16:30 地点:深圳腾讯大厦(南山区科技园科技中一路)2楼多功能厅 主办:APICloud.OneAPM.连接科技 网址:www.apicloud. ...

  7. thinkphp扩展 根据前端批量建立字段

    /*批量添加字段辅助*/ function add_colum($tabel){ foreach ($_POST as $key=>$value){ $array[] = "add & ...

  8. pmp培训.rar

    pmp培训.rar http://pan.baidu.com/s/1sleUQol

  9. Flume-ng+Kafka+storm的学习笔记

    Flume-ng Flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统. Flume的文档可以看http://flume.apache.org/FlumeUserGuide.html ...

  10. jQuery的delegate()与proxy()方法

    1. jQuery 事件 - delegate() 方法 定义和用法 delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数. 使用 ...