QueryBlock(查询块)¶
在查询语句中,系统会自动根据SELECT在SQL中出现得顺序给每个QueryBlock生成一个 SEL$ + 序号 组成的查询块名称, 形如 SEL$1、SEL$2...
用户可以通过在Hint中添加这些查询块名称来指定Hint生效的查询块,也可以通过在Hint的表名后添加查询块名称来指定表。
查看QueryBlock¶
在开启显示QueryBlock参数(ENABLE_DISPLAY_QUERY_BLOCK)后,可以通过Explain来查看表所属的QueryBlock
从下面的计划可以看到表上存在QueryBlock信息 T1@SEL$1 QueryBlock @SEL$1 和 T2@SEL$2 QueryBlock @SEL$2
T1@SEL$1 说明 T1 在SQL上属于第一个查询块(SEL$1),也就是第一个SELECT中
QueryBlock @SEL$1 说明 T1 在进行规则优化后,最后所属的查询块是第一个查询块(SEL$1)
T1@SEL$2 说明 T2 在SQL上属于第二个查询块(SEL$2),也就是第二个SELECT中
QueryBlock @SEL$2 说明 T2 在进行规则优化后,最后所属的查询块是第二个查询块(SEL$2)
-- 环境准备
create table t1(a int);
create table t2(a int);
create index idx1 on t1(a);
create index idx2 on t2(a);
-- 开启参数
set ENABLE_DISPLAY_QUERY_BLOCK = TRUE;
explain select * from t1,(select * from t2 where t2.a = 1 limit 1) where t1.a = 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Nested Loop(Inner Join) (cost=0.00..215.74 rows=10602 width=8)
-> Subquery Scan "__Anonymous_0" (cost=0.00..2.70 rows=1 width=4)
-> Limit (cost=0.00..2.70 rows=1 width=4)
-> Seq Scan on T2@SEL$2 QueryBlock @SEL$2 (cost=0.00..110.40 rows=1 width=4)
Scan Key: (A = 1)
-> Index Scan using IDX1(Fast Index Scan) on T1@SEL$1 QueryBlock @SEL$1 (cost=0.00..107.02 rows=10602 width=4)
Index Key: (A = 1)
(7 rows)
通过下面的计划更容易理解什么是表最后所属的查询块
对于 T2@SEL$2 QueryBlock @SEL$1 来说,因为T2在SQL上属于第二个查询块,所以仍然是T2@SEL$2,但是我们看到QueryBlock后变成了 @SEL$1
说明 T2 表最后所属的查询块是第一个查询块,这是因为 T2 表进行了子查询的提升,将其提升到了第一个查询块中。
explain select * from t1,(select * from t2 where t2.a = 1) where t1.a = 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Nested Loop(Inner Join) (cost=0.00..8840.82 rows=434246 width=8)
-> Seq Scan on T2@SEL$2 QueryBlock @SEL$1 (cost=0.00..110.40 rows=41 width=4)
Scan Key: (A = 1)
-> Index Scan using IDX1(Fast Index Scan) on T1@SEL$1 QueryBlock @SEL$1 (cost=0.00..107.02 rows=10602 width=4)
Index Key: (A = 1)
(5 rows)
在Hint中使用QueryBlock¶
方式一:
通过 EXPLAIN OUTLINE 可以查看组成此计划所需的Hint,这些Hint已经携带了QueryBlock信息
如果想控制表的扫描方式或者连接方式,可以直接复制 Outline 中的Hint进行修改
注解
推荐使用这种方式来使用带QueryBlock的Hint
explain outline select * from t1,(select * from t2 where t2.a = 1) where t1.a = 1;
QUERY PLAN
--------------------------------------------------------------------------------------
Nested Loop(Inner Join) (cost=0.00..261.57 rows=10602 width=8)
-> Index Scan using IDX2(Fast Index Scan) on T2 (cost=0.00..1.01 rows=1 width=4)
Index Key: (A = 1)
-> Seq Scan on T1 (cost=0.00..154.54 rows=10602 width=4)
Scan Key: (A = 1)
Outline
-------
INDEX(@SEL$1 SYSDBA.T2@SEL$2 IDX2)
FULL(@SEL$1 SYSDBA.T1@SEL$1)
USE_NL(@SEL$1 (SYSDBA.T2@SEL$2),(SYSDBA.T1@SEL$1))
(13 rows)
-- 如果想控制T2走顺序扫描,则将 Outline 中的 INDEX(@SEL$1 SYSDBA.T2@SEL$2 IDX2) 改为 full(@SEL$1 SYSDBA.T2@SEL$2) 即可
SQL=> explain select /*+ full(@SEL$1 SYSDBA.T2@SEL$2) */ * from t1,(select * from t2 where t2.a = 1) where t1.a = 1;
QUERY PLAN
------------------------------------------------------------------
Nested Loop(Inner Join) (cost=110.44..254.41 rows=1678 width=8)
-> Seq Scan on T1 (cost=0.00..110.40 rows=41 width=4)
Scan Key: (A = 1)
-> Materialize (cost=110.44..110.85 rows=41 width=4)
-> Seq Scan on T2 (cost=0.00..110.40 rows=41 width=4)
Scan Key: (A = 1)
Hint Report
-----------
Total hint num: 1
@SEL$1
- ENABLE
full(@sel$1 sysdba.t2@sel$2)
(16 rows)
方式二:
根据计划上显示的QueryBlock信息来构造Hint,Hint形式为 index(@SEL$1 T2@SEL$2)
Hint中最前面添加的@SEL$1指的是Hint作用的查询块为第一个查询块,表上指定的查询块T2@SEL$2指的是表在SQL上所属的查询块
简单来说,Hint的查询块应该添加计划上 QueryBlock 后的查询块,表上的查询块则直接使用计划上表的查询块即可
我们可以通过此 Hint 来控制下面计划中的 T2 表走索引扫描
explain select /*+ index(@SEL$1 T2@SEL$2) */ * from t1,(select * from t2 where t2.a = 1) where t1.a = 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Nested Loop(Inner Join) (cost=0.00..8731.84 rows=434246 width=8)
-> Index Scan using IDX2(Fast Index Scan) on T2@SEL$2 QueryBlock @SEL$1 (cost=0.00..1.41 rows=41 width=4)
Index Key: (A = 1)
-> Index Scan using IDX1(Fast Index Scan) on T1@SEL$1 QueryBlock @SEL$1 (cost=0.00..107.02 rows=10602 width=4)
Index Key: (A = 1)
Hint Report
-----------
Total hint num: 1
@SEL$1
- ENABLE
index(@sel$1 t2@sel$2)
(15 rows)
注解
指定了查询块的Hint应该添加到第一个查询块中
SEL$1可以省略,所以可以将 index(@SEL$1 T2@SEL$2) 写成 index(T2@SEL$2)
如果想控制 T1 走顺序扫描,那么可以将Hint写成 full(@SEL$1 T1@SEL$1) 或 full(T1)
explain select /*+ index(T2@SEL$2) full(T1) */ * from t1,(select * from t2 where t2.a = 1) where t1.a = 1;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Nested Loop(Inner Join) (cost=165.14..8855.71 rows=434246 width=8)
-> Index Scan using IDX2(Fast Index Scan) on T2@SEL$2 QueryBlock @SEL$1 (cost=0.00..1.41 rows=41 width=4)
Index Key: (A = 1)
-> Materialize (cost=165.14..271.16 rows=10602 width=4)
-> Seq Scan on T1@SEL$1 QueryBlock @SEL$1 (cost=0.00..154.54 rows=10602 width=4)
Scan Key: (A = 1)
Hint Report
-----------
Total hint num: 2
@SEL$1
- ENABLE
index(t2@sel$2)
full(t1)
(17 rows)