为什么在join on后面有or的条件执行计划只能走nested loop

[复制链接]
查看11 | 回复6 | 2015-9-25 14:27:26 | 显示全部楼层 |阅读模式
最近发现一个问题,如果在join on后面的条件中加入一段or的条件,执行计划就只能走nested loop,甚至加入Hint都是不允许的。实验情况如下:
1、创建表及构造数据
CREATE TABLE test_20151023(id int);
CREATE TABLE test_20151023_b(id INT, id1 int);
INSERT INTO test_20151023(id)
SELECT 1 id
UNION ALL
SELECT 2 id
UNION ALL
SELECT 3 id
UNION ALL
SELECT 400 id
UNION ALL
SELECT 500 id;
INSERT INTO test_20151023_b(id, id1)
SELECT 1 id, 100 id1
UNION
SELECT 2 id, 200 id1
UNION
SELECT 3 id, 300 id1
UNION
SELECT 4 id, 400 id1
UNION
SELECT 5 id, 500 id1
UNION
SELECT 6 id, 600 id1
UNION
SELECT 7 id, 700 id1
UNION
SELECT 8 id, 800 id1;
这样表test_20151023数据为:
id
1
2
3
400
500

test_20151023_b数据为:
id
id1
1
100
2
200
3
300
4
400
5
500
6
600
7
700
8
800

2、SQL语句如下:
SELECT b.*
FROM test_20151023 a
INNER JOIN test_20151023_b b
ON a.id = b.id
OR
a.id = b.id1

3、执行计划如下:


1.jpg (14.34 KB, 下载次数: 0)
下载附件
2015-10-23 13:31 上传

从执行计划中可以看出用的是nested loop连接方式
4、在SQL中加入hint,如下:
SELECT b.*
FROM test_20151023 a
INNER HASH JOIN test_20151023_b b
ON a.id = b.id
OR
a.id = b.id1

这里我加入了hash,但是数据库会提示错误,如下:
“消息 8622,级别 16,状态 1,第 1 行
由于此查询中定义了提示,查询处理器未能生成查询计划。请重新提交查询,并且不要在查询中指定任何提示,也不要使用 SET FORCEPLAN。”

5、如果将语句中的OR后面一段注释的话是可以的:
SELECT b.*
FROM test_20151023 a
INNER HASH JOIN test_20151023_b b
ON a.id = b.id
--OR
--a.id = b.id1

想问一下这是什么原理?
是因为当ON后面有OR条件时,执行计划有且只能走nested loop这种方式吗?
如果是的话,原理是什么呢?
还望给予答案,谢谢!



回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
Similar to a merge join, a hash join can be used only if there is at least one equality
回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
这个问题就是因为SQL引擎优化,导致的强制使用的hint,hash match条件不满足造成的异常。

回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
本帖最后由 佚名是译名 于 2015-10-23 17:37 编辑
如果非要用hash的话,就要这样写了
SELECT b.*
FROM test_20151023 a
INNER hash JOIN test_20151023_b b ON a.id = b.id
union
SELECT b.*
FROM test_20151023 a
INNER hash JOIN test_20151023_b b on a.id = b.id1

回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
你那种hash写法,分析器优化时第二个or条件会省略谓语,导致执行第二个的时候出错。
在sql server 2012上好像不会出错了,执行时强制把谓语加上去了。
回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
条件加OR不是好习惯,CBO动不动走用笨办法的。因为要考虑得太多了吧。你分开来写就很明显。一用OR,基本就是NESTEDLOOP,FULL TABLE ACCESS,FILTER的套路了。
回复

使用道具 举报

千问 | 2015-9-25 14:27:26 | 显示全部楼层
优化器就是这样的
SELECT b.*
FROM test_20151023 a
INNER HASH JOIN test_20151023_b b
ON a.id = b.id
union
SELECT b.*
FROM test_20151023 a
INNER HASH JOIN test_20151023_b b
ON a.id = b.id1
这样改写下就可以了,一般不要在谓词里加OR
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行