如何向以下示例添加索引

u5rb5r59  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(307)
SELECT UNIT_PRICE
FROM ORDER_DETAIL
WHERE QUANTITY IN (100, 200, 300) OR
DISCOUNT = 0.01;

我的问题:

EXPLAIN PLAN FOR SELECT UNIT_PRICE FROM ORDER_DETAIL WHERE QUANTITY IN (100, 200, 300) OR DISCOUNT = 0.01;`
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
CREATE INDEX OD_IDX_QD ON ORDER_DETAIL(QUANTITY, DISCOUNT);
EXPLAIN PLAN FOR SELECT UNIT_PRICE FROM ORDER_DETAIL WHERE QUANTITY IN (100, 200, 300) OR DISCOUNT = 0.01;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
DROP INDEX OD_IDX_QD;



在这种情况下如何正确添加索引

ddarikpa

ddarikpa1#

您的查询包含或,这就是您无法获取索引范围扫描的原因。您可以为折扣再创建一个索引并添加提示或扩展,在这种情况下,您将通过两个索引范围扫描(或扩展转换)获得union all
(oracle 12.2+:https://blogs.oracle.com/optimizer/optimizer-transformations:-或扩展)

CREATE INDEX OD_IDX_D ON ORDER_DETAIL(DISCOUNT);

EXPLAIN PLAN FOR 
SELECT/*+ or_expand */ UNIT_PRICE FROM ORDER_DETAIL WHERE QUANTITY IN (100, 200, 300) OR DISCOUNT = 0.01;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- output
Plan hash value: 4033578183

----------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                 |     4 |    52 |     5   (0)| 00:00:01 |
|   1 |  VIEW                                  | VW_ORE_1606201E |     4 |    52 |     5   (0)| 00:00:01 |
|   2 |   UNION-ALL                            |                 |       |       |            |          |
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED | ORDER_DETAIL    |     1 |    26 |     2   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN                   | OD_IDX_D        |     1 |       |     1   (0)| 00:00:01 |
|   5 |    INLIST ITERATOR                     |                 |       |       |            |          |
|   6 |     TABLE ACCESS BY INDEX ROWID BATCHED| ORDER_DETAIL    |     3 |    90 |     3   (0)| 00:00:01 |
|*  7 |      INDEX RANGE SCAN                  | OD_IDX_QD       |     3 |       |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("DISCOUNT"=0.01)
   7 - access("QUANTITY"=100 OR "QUANTITY"=200 OR "QUANTITY"=300)
       filter(LNNVL("DISCOUNT"=0.01))

或者,如果您的oracle版本很旧,可以使用hint use \u concat:

CREATE INDEX OD_IDX_D ON ORDER_DETAIL(DISCOUNT);

EXPLAIN PLAN FOR 
SELECT/*+ use_concat */ UNIT_PRICE 
FROM ORDER_DETAIL OD
WHERE QUANTITY IN (100, 200, 300) OR DISCOUNT = 0.01;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Plan hash value: 819751077

------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |              |     4 |   120 |     5   (0)| 00:00:01 |
|   1 |  CONCATENATION                        |              |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | ORDER_DETAIL |     1 |    30 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                   | OD_IDX_D     |     1 |       |     1   (0)| 00:00:01 |
|   4 |   INLIST ITERATOR                     |              |       |       |            |          |
|   5 |    TABLE ACCESS BY INDEX ROWID BATCHED| ORDER_DETAIL |     3 |    90 |     3   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN                  | OD_IDX_QD    |     3 |       |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("DISCOUNT"=0.01)
   6 - access("QUANTITY"=100 OR "QUANTITY"=200 OR "QUANTITY"=300)
       filter(LNNVL("DISCOUNT"=0.01))

更新:评论不方便回答您的其他问题,所以我在这里回答:
因为您的查询包含或:

WHERE QUANTITY IN (100, 200, 300) OR DISCOUNT = 0.01;

如果您分析您的查询,您可以发现这与

select UNIT_PRICE 
from (
    SELECT rowid, UNIT_PRICE FROM ORDER_DETAIL WHERE QUANTITY IN (100, 200, 300) 
    union
    SELECT rowid, UNIT_PRICE FROM ORDER_DETAIL WHERE DISCOUNT = 0.01
)

其中union all的第一部分可以使用您的索引,因为它从该列开始,而不是从第二部分开始,因为您没有为索引的第一列提供范围。在这种情况下,oracle可以使用index skip scan,但在这种情况下它不起作用。所以你需要另一个索引。

相关问题