大表关联如何通过hint指定主键索引

【 使用环境 】测试环境
【问题描述】
举例A/B两表关联,语句如:
SELECT * FROM A,B WHERE A.C1=B.C1 AND A.C2=‘X’;
A表B表的主键都是C1,A表存在索引C2字段,可以用hint指定A为主表,并指定用NL关联模式,B表关联时使用主键索引吗?我原本尝试index(B primary),但是观察下来这个等价于full(B),explain提示确实变成了table full scan,不满足我想要的效果。是否无法指定主键,而需要建立一个同样列的唯一索引进行index hint指定?

你这个sql比较简单,走 NL 的时候,访问 B 表就是走索引。只不过 OB 的主键索引就是表数据自身,所以访问主键就是访问表。正常来说会看到对 B 表 的 TABLE GET(B).

不过,如果B 表数据量不大的情况下且C1就是主键,OB 可能会优化这个执行计划,对B 表的结果集直接进行 物化处理(加入 MATERIAL 算子),此时就对 B 表主键进行 FULL SCAN 了。这个优化好像没法取消。

(root@127.1:2883) [test]> explain select /*+ use_nl(c,w) */ w.w_name,c.c_last,c.c_first,c.c_credit from bmsql_warehouse w, bmsql_customer c where w.w_id=c.c_w_id and c.c_last='BARBARESE';
+--------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------------------+
| =====================================================================                                                                      |
| |ID|OPERATOR           |NAME                  |EST.ROWS|EST.TIME(us)|                                                                      |
| ---------------------------------------------------------------------                                                                      |
| |0 |NESTED-LOOP JOIN   |                      |53      |146         |                                                                      |
| |1 |├─TABLE RANGE SCAN |c(bmsql_customer_ind1)|53      |138         |                                                                      |
| |2 |└─MATERIAL         |                      |4       |5           |                                                                      |
| |3 |  └─TABLE FULL SCAN|w                     |4       |4           |                                                                      |
| =====================================================================                                                                      |
| Outputs & filters:                                                                                                                         |
| -------------------------------------                                                                                                      |
|   0 - output([w.w_name], [c.c_last], [c.c_first], [c.c_credit]), filter(nil), rowset=256                                                   |
|       conds([w.w_id = c.c_w_id]), nl_params_(nil), use_batch=false                                                                         |
|   1 - output([c.c_w_id], [c.c_last], [c.c_first], [c.c_credit]), filter(nil), rowset=256                                                   |
|       access([c.c_w_id], [c.c_d_id], [c.c_id], [c.c_last], [c.c_first], [c.c_credit]), partitions(p0)                                      |
|       is_index_back=true, is_global_index=false,                                                                                           |
|       range_key([c.c_last], [c.c_first], [c.c_w_id], [c.c_d_id], [c.c_id]), range(BARBARESE,MIN,MIN,MIN,MIN ; BARBARESE,MAX,MAX,MAX,MAX),  |
|       range_cond([c.c_last = cast('BARBARESE', VARCHAR(1048576))])                                                                         |
|   2 - output([w.w_name], [w.w_id]), filter(nil), rowset=256                                                                                |
|   3 - output([w.w_id], [w.w_name]), filter(nil), rowset=256                                                                                |
|       access([w.w_id], [w.w_name]), partitions(p0)                                                                                         |
|       is_index_back=false, is_global_index=false,                                                                                          |
|       range_key([w.__pk_increment]), range(MIN ; MAX)always true                                                                           |
+--------------------------------------------------------------------------------------------------------------------------------------------+
22 rows in set (0.01 sec)

参考:

2 个赞

请将执行计划发一下