你应该接受那些一般性的建议索引是好的,全表扫描是不好的!要小心。
它总是取决于使用的上下文。
我重新编写您的示例,删除不相关的部分并使用中性列名
我还添加了 alias 来限定列,因此可以清楚地从哪个表中获取列。
SELECT a.id, a.col1, a.col2, a.col3,
b.col4
FROM a
LEFT OUTER JOIN b
ON a.id = b.fk_id AND
b.col1 = 8 AND
b.col2 IS NULL AND
b.col3 IS NULL
请注意,在连接中,您选择表 A 中的所有行 - 这意味着 没有用于访问表 A 的索引会有所帮助。您必须全面扫描表并处理所有行。
您将看到 HASH JOIN 作为已使用的连接操作,如果您连接大型数据集,这是首选选项。
查看here如何获取查询的执行计划。
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 1044K| 25 (4)| 00:00:01 |
|* 1 | HASH JOIN RIGHT OUTER| | 10000 | 1044K| 25 (4)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | B | 2 | 110 | 16 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | A | 10000 | 507K| 8 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."ID"="B"."FK_ID"(+))
2 - filter("B"."COL3"(+) IS NULL AND "B"."COL2"(+) IS NULL AND
"B"."COL1"(+)=8)
如果您将表 A 中已处理的行限制为一个非常小的数字,例如使用带有附加 WHERE 条件的相同查询,则会出现不同的情况。
您将使用 嵌套循环 连接和索引访问来仅获取所需的行。
SELECT a.id, a.col1, a.col2, a.col3,
b.col4
FROM a
LEFT OUTER JOIN b
ON a.id = b.fk_id AND
b.col1 = 8 AND
b.col2 IS NULL AND
b.col3 IS NULL
where a.id = 8 --<<<< here you select only a few rows
现在您可以从定义索引中获利
- 使用
WHERE 谓词访问表A
- 使用
join 列访问表B
在我们的例子中是
create index a_idx on a (id);
create index b_idx on b (fk_id,col1, col2, col3);
您应该期望的执行计划将是嵌套循环外部连接
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 214 | 4 (0)| 00:00:01 |
| 1 | NESTED LOOPS OUTER | | 2 | 214 | 4 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| A | 1 | 52 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | A_IDX | 1 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| B | 2 | 110 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | B_IDX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."ID"=8)
5 - access("B"."FK_ID"(+)=8 AND "B"."COL1"(+)=8 AND "B"."COL2"(+) IS NULL
AND "B"."COL3"(+) IS NULL)
filter("B"."COL3"(+) IS NULL)