我已经尝试解释和显示这个查询的执行计划。
解释计划
SELECT *
FROM LINEITEM
WHERE l_quantity = 6
OR l_shipMode = 'MAIL';
SELECT * FROM table(dbms_xplan.display);
输出是。
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 98068815
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 287K| 34M| 8802 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| LINEITEM | 287K| 34M| 8802 (1)| 00:00:01 |
------------------------------------------------------------------------------
然后我创建了一个索引 l_quantity
和 l_shipMode
:
CREATE INDEX lineItemIdx ON LINEITEM(l_quantity, l_shipMode);
然后我再解释并展示执行计划。
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 98068815
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 287K| 34M| 8802 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| LINEITEM | 287K| 34M| 8802 (1)| 00:00:01 |
------------------------------------------------------------------------------
没有区别。现在的查询不应该使用索引吗?
唉,大多数数据库的优化工作做得非常差劲。or
表达式(Oracle是个例外)。
你可以使用 union all
:
SELECT li.*
FROM LINEITEM li
WHERE l_quantity = 6
UNION ALL
SELECT li.*
FROM LINEITEM li
WHERE l_shipMode = 'MAIL' AND l_quantity <> 6;
为此,你需要 两种 指数。 LINEITEM(l_quantity)
和 LINEITEM(l_shipMode, l_quantity)
.
在你的查询中,你有两个条件,并结合一个 OR
子句。
WHERE l_quantity = 6
OR l_shipMode = 'MAIL';
这就意味着,对于过滤标准的评价,指数为
INDEX lineItemIdx ON LINEITEM(l_quantity, l_shipMode);
对于OR子句的两个部分中的每一部分都不能正常工作......。
所以查询需要全盘扫描,索引在没有用。
在这种情况下,索引只有在条件为
WHERE l_quantity = 6
或
WHERE l_quantity = 6
AND l_shipMode = 'MAIL';
或者使用两个索引,然后重建查询,基于UNION的两个分离查询。