• Oracle 利用执行计划来避免排序操作


    在oracle中,利用index来避免排序

    SQL> CREATE TABLE T_NOSORT (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30) NOT NULL);
    SQL> CREATE INDEX IND_T_NOSORT_NAME ON T_NOSORT(NAME);
    SQL> INSERT INTO T_NOSORT SELECT ROWNUM, TABLE_NAME FROM USER_TABLES;
    SQL> COMMIT;
    SQL> SET AUTOT ON EXP
    SQL> SELECT ID, NAME FROM T_NOSORT ORDER BY NAME;
    ----------------------------------------------------------
    Plan hash value: 1041838668
    -------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    -------------------------------------------------------
    | 0 | SELECT STATEMENT | | 15 | 450 |
    | 1 | SORT ORDER BY | | 15 | 450 |
    | 2 | TABLE ACCESS FULL| T_NOSORT | 15 | 450 |
    -------------------------------------------------------
    QL> SELECT /*+ INDEX(T_NOSORT IND_T_NOSORT_NAME) */ ID, NAME FROM T_NOSORT ORDER BY NAME;
    | Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------|   0 | SELECT STATEMENT          |                   |    41 |  1230 |   827   (1)| 00:00:10 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T_NOSORT          |    41 |  1230 |   827   (1)| 00:00:10 |
    |   2 |   INDEX FULL SCAN           | IND_T_NOSORT_NAME |    41 |       |    26   (0)| 00:00:01 |

    利用索引范围扫描

    SQL> SELECT ID, NAME FROM T_NOSORT WHERE NAME < 'I' ORDER BY NAME;
    ----------------------------------------------------------
    Plan hash value: 1041838668
    -------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    -------------------------------------------------------
    | 0 | SELECT STATEMENT | | 9 | 270 |
    | 1 | SORT ORDER BY | | 9 | 270 |
    |* 2 | TABLE ACCESS FULL| T_NOSORT | 9 | 270 |
    -------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    2 - filter("NAME"<'I')
    SQL> SELECT /*+ INDEX(T_NOSORT IND_T_NOSORT_NAME) */ ID, NAME 
    2 FROM T_NOSORT WHERE NAME < 'I' ORDER BY NAME;
    ----------------------------------------------------------
    Plan hash value: 919790285
    -------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    -------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 9 | 270 |
    | 1 | TABLE ACCESS BY INDEX ROWID| T_NOSORT | 9 | 270 |
    |* 2 | INDEX RANGE SCAN | IND_T_NOSORT_NAME | 9 | |
    -------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    2 - access("NAME"<'I')
    filter("NAME"<'I')

    如果是倒序排序

    QL> SELECT /*+ INDEX_DESC(T_NOSORT IND_T_NOSORT_NAME) */ ID, NAME 
    2 FROM T_NOSORT ORDER BY NAME DESC;
    ----------------------------------------------------------
    Plan hash value: 2858378269
    -------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    -------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 15 | 450 |
    | 1 | TABLE ACCESS BY INDEX ROWID| T_NOSORT | 15 | 450 |
    | 2 | INDEX FULL SCAN DESCENDING| IND_T_NOSORT_NAME | 15 | |
    -------------------------------------------------------------------------

    这里只是说明了能够避免排序的执行计划,但是不一定能提升性能

    上面针对于单表

    MERGE JOIN连接方式

    SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30) NOT NULL);
    SQL> CREATE TABLE T2 (ID NUMBER, NAME VARCHAR2(30));
    SQL> CREATE INDEX IND_T1_NAME ON T1(NAME);
    SQL> INSERT INTO T1 SELECT ROWNUM, TABLE_NAME FROM USER_TABLES;
    SQL> INSERT INTO T2 SELECT ROWNUM, OBJECT_NAME FROM USER_OBJECTS;
    SQL> COMMIT;
    SQL> SET AUTOT ON EXP
    SQL> SELECT /*+ USE_MERGE(T1, T2) */ T2.NAME, T1.ID FROM T1, T2
     WHERE T1.NAME = T2.NAME ;
    | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |    41 |  1927 |     8  (25)| 00:00:01 |
    |   1 |  MERGE JOIN         |      |    41 |  1927 |     8  (25)| 00:00:01 |
    |   2 |   SORT JOIN         |      |    41 |  1230 |     4  (25)| 00:00:01 |
    |   3 |    TABLE ACCESS FULL| T1   |    41 |  1230 |     3   (0)| 00:00:01 |
    |*  4 |   SORT JOIN         |      |    99 |  1683 |     4  (25)| 00:00:01 |
    |   5 |    TABLE ACCESS FULL| T2   |    99 |  1683 |     3   (0)| 00:00:01 |
    ----------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    4 - access("T1"."NAME"="T2"."NAME")
    filter("T1"."NAME"="T2"."NAME")
    SQL> SELECT /*+ USE_MERGE(T2, T1) */ T2.NAME, T1.ID
     FROM T1, T2 WHERE T1.NAME = T2.NAME ORDER BY T2.NAME ;
    ----------------------------------------------------
    Plan hash value: 412793182
    ----------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    ----------------------------------------------------
    | 0 | SELECT STATEMENT | | 19 | 893 |
    | 1 | MERGE JOIN | | 19 | 893 |
    | 2 | SORT JOIN | | 17 | 510 |
    | 3 | TABLE ACCESS FULL| T1 | 17 | 510 |
    |* 4 | SORT JOIN | | 97 | 1649 |
    | 5 | TABLE ACCESS FULL| T2 | 97 | 1649 |
    ----------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    4 - access("T1"."NAME"="T2"."NAME")
    filter("T1"."NAME"="T2"."NAME")

    针对merge join只能对连接的列排序,且排序操作只能是升序

    SQL> SELECT /*+ USE_MERGE(T2, T1) */ T2.NAME, T1.ID
     FROM T1, T2 WHERE T1.NAME = T2.NAME ORDER BY T2.NAME DESC;
    |   0 | SELECT STATEMENT     |      |    41 |  1927 |     9  (34)| 00:00:01 |
    |   1 |  SORT ORDER BY       |      |    41 |  1927 |     9  (34)| 00:00:01 |
    |   2 |   MERGE JOIN         |      |    41 |  1927 |     8  (25)| 00:00:01 |
    |   3 |    SORT JOIN         |      |    41 |  1230 |     4  (25)| 00:00:01 |
    |   4 |     TABLE ACCESS FULL| T1   |    41 |  1230 |     3   (0)| 00:00:01 |
    |*  5 |    SORT JOIN         |      |    99 |  1683 |     4  (25)| 00:00:01 |
    |   6 |     TABLE ACCESS FULL| T2   |    99 |  1683 |     3   (0)| 00:00:01 |5 - access("T1"."NAME"="T2"."NAME")
    filter("T1"."NAME"="T2"."NAME")

    NESTED LOOP连接

    由于nested loop不会对操作结果排序,所以结果是无序的

    如果驱动表在连接前是有序的,在连接后,结果还是有序的

    SQL> CREATE INDEX IND_T2_ID ON T2(ID);
    SQL> CREATE INDEX IND_T2_NAME ON T2(NAME);
    SQL> SELECT /*+ USE_NL(T1, T2) */ T1.ID, T1.NAME, T2.NAME 
    2 FROM T1, T2
    3 WHERE T1.ID = T2.ID
    4 ;
    ----------------------------------------------------------
    Plan hash value: 3621112097
    ----------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost
    ----------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 17 | 1020 | 
    | 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 30 | 
    | 2 | NESTED LOOPS | | 17 | 1020 | 
    | 3 | TABLE ACCESS FULL | T1 | 17 | 510 | 
    |* 4 | INDEX RANGE SCAN | IND_T2_ID | 1 | | 
    ----------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    4 - access("T1"."ID"="T2"."ID")
    SQL> SELECT /*+ ORDERED INDEX(T1 IND_T1_NAME) USE_NL(T1, T2) */ 
    2 T1.ID, T1.NAME, T2.NAME 
    3 FROM T1, T2
    4 WHERE T1.ID = T2.ID
    5 ORDER BY T1.NAME
    6 ;
    
    ----------------------------------------------------------
    Plan hash value: 1062594094
    ---------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    ---------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 17 | 1020 |
    | 1 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 30 |
    | 2 | NESTED LOOPS | | 17 | 1020 |
    | 3 | TABLE ACCESS BY INDEX ROWID| T1 | 17 | 510 |
    | 4 | INDEX FULL SCAN | IND_T1_NAME | 17 | |
    |* 5 | INDEX RANGE SCAN | IND_T2_ID | 1 | |
    ---------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    5 - access("T1"."ID"="T2"."ID")
    SQL> ALTER TABLE T2 MODIFY NAME NOT NULL;
    SQL> CREATE INDEX IND_T2_NAME ON T2(NAME);
    SQL> SET AUTOT OFF
    SQL> UPDATE T2 SET ID = MOD(ID, 17) + 1;
    SQL> COMMIT;
    SQL> SET AUTOT ON EXP
    SQL> SELECT /*+ ORDERED INDEX(T1 IND_T1_NAME) 
    2 INDEX(T2 IND_T2_NAME) USE_NL(T1, T2) */ 
    3 T1.ID, T1.NAME, T2.NAME 
    4 FROM T1, T2
    5 WHERE T1.ID = T2.ID
    6 ORDER BY T1.NAME
    7 ;
    ----------------------------------------------------------
    Plan hash value: 3719138605
    ---------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    ---------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 97 | 5820 |
    |* 1 | TABLE ACCESS BY INDEX ROWID | T2 | 6 | 180 |
    | 2 | NESTED LOOPS | | 97 | 5820 |
    | 3 | TABLE ACCESS BY INDEX ROWID| T1 | 17 | 510 |
    | 4 | INDEX FULL SCAN | IND_T1_NAME | 17 | |
    | 5 | INDEX FULL SCAN | IND_T2_NAME | 97 | |
    ---------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    1 - filter("T1"."ID"="T2"."ID")
    
    SQL> SELECT /*+ ORDERED INDEX(T1 IND_T1_NAME) 
    2 INDEX_DESC(T2 IND_T2_NAME) USE_NL(T1, T2) */ 
    3 T1.ID, T1.NAME, T2.NAME 
    4 FROM T1, T2
    5 WHERE T1.ID = T2.ID
    6 ORDER BY T1.NAME
    7 ;
    ----------------------------------------------------------
    Plan hash value: 2531946081
    ---------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    ---------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 97 | 5820 |
    |* 1 | TABLE ACCESS BY INDEX ROWID | T2 | 6 | 180 |
    | 2 | NESTED LOOPS | | 97 | 5820 |
    | 3 | TABLE ACCESS BY INDEX ROWID| T1 | 17 | 510 |
    | 4 | INDEX FULL SCAN | IND_T1_NAME | 17 | |
    | 5 | INDEX FULL SCAN DESCENDING | IND_T2_NAME | 97 | |
    ---------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    1 - filter("T1"."ID"="T2"."ID")
    SQL> SELECT /*+ ORDERED INDEX(T1 IND_T1_NAME) 
    2 INDEX(T2 IND_T2_NAME) USE_NL(T1, T2) */ 
    3 T1.ID, T1.NAME, T2.NAME 
    4 FROM T1, T2
    5 WHERE T1.ID = T2.ID
    6 ORDER BY T1.NAME, T2.NAME DESC
    7 ;
    
    ----------------------------------------------------------
    Plan hash value: 1438746903
    ----------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes |
    ----------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 97 | 5820 |
    | 1 | SORT ORDER BY | | 97 | 5820 |
    |* 2 | TABLE ACCESS BY INDEX ROWID | T2 | 6 | 180 |
    | 3 | NESTED LOOPS | | 97 | 5820 |
    | 4 | TABLE ACCESS BY INDEX ROWID| T1 | 17 | 510 |
    | 5 | INDEX FULL SCAN | IND_T1_NAME | 17 | |
    | 6 | INDEX FULL SCAN | IND_T2_NAME | 97 | |
    ----------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    2 - filter("T1"."ID"="T2"."ID")
  • 相关阅读:
    学号20145332 《信息安全系统设计基础》实验二 固件设计
    第九周学习总结
    学号20145332 《信息安全系统设计基础》期中总结
    学号20145332 《信息安全系统设计基础》实验一 开发环境的熟悉
    第七周学习总结
    第六周学习总结
    第五周学习总结
    第三周学习总结
    第二周学习总结
    第一周学习总结
  • 原文地址:https://www.cnblogs.com/yhq1314/p/10594572.html
Copyright © 2020-2023  润新知