1. 程式人生 > >使用UNION代替OR 提升查詢效能

使用UNION代替OR 提升查詢效能

昨天一位鐵哥們通過QQ找我幫忙,問下面這個SQL能否優化

SQL> set timing on
SQL> set autotrace on
SQL> select count(*) rowcount_lhy
  2    from swgl_ddjbxx t
  3   where t.fzgs_dm = '001085'
  4     and (t.lrr_dm = 'e90e3fe4237c4af988477329c7f2059e' or exists
  5          (select y.kh_id
  6             from khgl_khywdlxx y
  7            where y.kh_id = t.kh_id
  8              and y.sskhjl_dm = 'e90e3fe4237c4af988477329c7f2059e') or
  9          t.kpr_dm = 'e90e3fe4237c4af988477329c7f2059e')
 10     and t.xjbz = '9999'
 11     and t.FROMNBGL1 = '0';

 

SQL> set line  300
SQL> /

ROWCOUNT_LHY
------------
          60

已用時間:  00: 00: 20.53

執行計劃
----------------------------------------------------------
Plan hash value: 1217125969

--------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                        |     1 |    86 | 28048   (1)| 00:05:37 |
|   1 |  SORT AGGREGATE               |                        |     1 |    86 |            |          |
|*  2 |   FILTER                      |                        |       |       |            |          |
|*  3 |    TABLE ACCESS FULL          | SWGL_DDJBXX            |  5926 |   497K| 28048   (1)| 00:05:37 |
|*  4 |    TABLE ACCESS BY INDEX ROWID| KHGL_KHYWDLXX          |     1 |    57 |     5   (0)| 00:00:01 |
|*  5 |     INDEX RANGE SCAN          | IDX_KHGL_KHYWDLXX_KHID |     1 |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------

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

   2 - filter("T"."LRR_DM"='e90e3fe4237c4af988477329c7f2059e' OR
              "T"."KPR_DM"='e90e3fe4237c4af988477329c7f2059e' OR  EXISTS (SELECT 0 FROM "KHGL_KHYWDLXX" "Y"
              WHERE "Y"."KH_ID"=:B1 AND "Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e'))
   3 - filter("T"."FROMNBGL1"='0' AND "T"."XJBZ"='9999' AND "T"."FZGS_DM"='001085')
   4 - filter("Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e')
   5 - access("Y"."KH_ID"=:B1)


統計資訊
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     804560  consistent gets
      71127  physical reads
          0  redo size
        516  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


看了5秒鐘,回覆哥們說把or展開成union,但是那哥們SQL確實太菜了呵呵(別罵我哈),只好幫忙寫一個了

SQL> select count(*)
  2    from (select *
  3            from swgl_ddjbxx t
  4           where t.lrr_dm = 'e90e3fe4237c4af988477329c7f2059e'
  5             and t.fzgs_dm = '001085'
  6             and t.xjbz = '9999'
  7             and t.FROMNBGL1 = '0'
  8          union
  9          select *
 10            from swgl_ddjbxx t
 11           where t.kpr_dm = 'e90e3fe4237c4af988477329c7f2059e'
 12             and t.fzgs_dm = '001085'
 13             and t.xjbz = '9999'
 14             and t.FROMNBGL1 = '0'
 15          union
 16          select *
 17            from swgl_ddjbxx t
 18           where exists
 19           (select y.kh_id
 20                    from khgl_khywdlxx y
 21                   where y.kh_id = t.kh_id
 22                     and y.sskhjl_dm = 'e90e3fe4237c4af988477329c7f2059e')
 23             and t.fzgs_dm = '001085'
 24             and t.xjbz = '9999'
 25             and t.FROMNBGL1 = '0');

  COUNT(*)
----------
        60

已用時間:  00: 00: 06.89

執行計劃
----------------------------------------------------------
Plan hash value: 3846872744

-----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name                     | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                          |     1 |       |       | 52263   (1)| 00:10:28 |
|   1 |  SORT AGGREGATE                    |                          |     1 |       |       |         |             |
|   2 |   VIEW                             |                          |  5996 |       |       | 52263   (1)| 00:10:28 |
|   3 |    SORT UNIQUE                     |                          |  5996 |  2238K|  6344K| 52263  (47)| 00:10:28 |
|   4 |     UNION-ALL                      |                          |       |       |       |         |             |
|*  5 |      TABLE ACCESS FULL             | SWGL_DDJBXX              |    59 | 19234 |       | 28037   (1)| 00:05:37 |
|*  6 |      TABLE ACCESS BY INDEX ROWID   | SWGL_DDJBXX              |    10 |  3260 |       |  1209   (1)| 00:00:15 |
|*  7 |       INDEX RANGE SCAN             | IDX_SWGL_DDJBXX_KPRDM    |  4748 |       |       |    34   (0)| 00:00:01 |
|*  8 |      TABLE ACCESS BY INDEX ROWID   | SWGL_DDJBXX              |     1 |   326 |       |     5   (0)| 00:00:01 |
|   9 |       NESTED LOOPS                 |                          |  5927 |  2216K|       | 22527   (1)| 00:04:31 |
|  10 |        SORT UNIQUE                 |                          | 10165 |   565K|       |  1916   (1)| 00:00:23 |
|  11 |         TABLE ACCESS BY INDEX ROWID| KHGL_KHYWDLXX            | 10165 |   565K|       |  1916   (1)| 00:00:23 |
|* 12 |          INDEX RANGE SCAN          | IDX_KHGL_KHYWDLXX_SSKHJL | 10165 |       |       |   111   (0)| 00:00:02 |
|* 13 |        INDEX RANGE SCAN            | IDX_SWGL_DDJBXX_KHID     |     2 |       |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------

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

   5 - filter("T"."LRR_DM"='e90e3fe4237c4af988477329c7f2059e' AND "T"."FROMNBGL1"='0' AND "T"."XJBZ"='9999'
              AND "T"."FZGS_DM"='001085')
   6 - filter("T"."FROMNBGL1"='0' AND "T"."XJBZ"='9999' AND "T"."FZGS_DM"='001085')
   7 - access("T"."KPR_DM"='e90e3fe4237c4af988477329c7f2059e')
   8 - filter("T"."FROMNBGL1"='0' AND "T"."XJBZ"='9999' AND "T"."FZGS_DM"='001085')
  12 - access("Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e')
  13 - access("Y"."KH_ID"="T"."KH_ID")


統計資訊
----------------------------------------------------------
          1  recursive calls
          0  db block gets
     128422  consistent gets
      10308  physical reads
          0  redo size
        512  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
          1  rows processed


SQL改寫之後,執行時間由原來的20秒下降到6秒,邏輯讀由804560降低到128422,效能還是有很大提升的,到了這裡優化還沒完,可以建立一個組合索引進一步優化

create index idx on swgl_ddjbxx(fzgs_dm,xjbz,FROMNBGL1);

建立索引之後,原始的SQL執行時間,執行計劃,統計資訊如下:

SQL> select count(*) rowcount_lhy
  2    from swgl_ddjbxx t
  3   where t.fzgs_dm = '001085'
  4     and (t.lrr_dm = 'e90e3fe4237c4af988477329c7f2059e' or exists
  5          (select y.kh_id
  6             from khgl_khywdlxx y
  7            where y.kh_id = t.kh_id
  8              and y.sskhjl_dm = 'e90e3fe4237c4af988477329c7f2059e') or
  9          t.kpr_dm = 'e90e3fe4237c4af988477329c7f2059e')
 10     and t.xjbz = '9999'
 11     and t.FROMNBGL1 = '0';

ROWCOUNT_LHY
------------
          60

已用時間:  00: 00: 02.96

執行計劃
----------------------------------------------------------
Plan hash value: 3049366449

--------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                        |     1 |    86 |   506   (0)| 00:00:07 |
|   1 |  SORT AGGREGATE               |                        |     1 |    86 |            |          |
|*  2 |   FILTER                      |                        |       |       |            |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| SWGL_DDJBXX            |  5926 |   497K|   506   (0)| 00:00:07 |
|*  4 |     INDEX RANGE SCAN          | IDX                    |  2370 |       |    12   (0)| 00:00:01 |
|*  5 |    TABLE ACCESS BY INDEX ROWID| KHGL_KHYWDLXX          |     1 |    57 |     5   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN          | IDX_KHGL_KHYWDLXX_KHID |     1 |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------

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

   2 - filter("T"."LRR_DM"='e90e3fe4237c4af988477329c7f2059e' OR
              "T"."KPR_DM"='e90e3fe4237c4af988477329c7f2059e' OR  EXISTS (SELECT 0 FROM "KHGL_KHYWDLXX" "Y"
              WHERE "Y"."KH_ID"=:B1 AND "Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e'))
   4 - access("T"."FZGS_DM"='001085' AND "T"."XJBZ"='9999' AND "T"."FROMNBGL1"='0')
   5 - filter("Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e')
   6 - access("Y"."KH_ID"=:B1)


統計資訊
----------------------------------------------------------
          1  recursive calls
          0  db block gets
     702767  consistent gets
          0  physical reads
          0  redo size
        516  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

改寫的SQL:

SQL> select count(*)
  2    from (select *
  3            from swgl_ddjbxx t
  4           where t.lrr_dm = 'e90e3fe4237c4af988477329c7f2059e'
  5             and t.fzgs_dm = '001085'
  6             and t.xjbz = '9999'
  7             and t.FROMNBGL1 = '0'
  8          union
  9          select *
 10            from swgl_ddjbxx t
 11           where t.kpr_dm = 'e90e3fe4237c4af988477329c7f2059e'
 12             and t.fzgs_dm = '001085'
 13             and t.xjbz = '9999'
 14             and t.FROMNBGL1 = '0'
 15          union
 16          select *
 17            from swgl_ddjbxx t
 18           where exists
 19           (select y.kh_id
 20                    from khgl_khywdlxx y
 21                   where y.kh_id = t.kh_id
 22                     and y.sskhjl_dm = 'e90e3fe4237c4af988477329c7f2059e')
 23             and t.fzgs_dm = '001085'
 24             and t.xjbz = '9999'
 25             and t.FROMNBGL1 = '0');

  COUNT(*)
----------
        60

已用時間:  00: 00: 00.53

執行計劃
----------------------------------------------------------
Plan hash value: 2947849958

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                     | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                          |     1 |       |       |  3469   (1)| 00:00:42 |
|   1 |  SORT AGGREGATE                      |                          |     1 |       |       |         |             |
|   2 |   VIEW                               |                          |  5995 |       |       |  3469   (1)| 00:00:42 |
|   3 |    SORT UNIQUE                       |                          |  5995 |  2238K|  4760K|  3469  (86)| 00:00:42 |
|   4 |     UNION-ALL                        |                          |       |       |       |         |             |
|*  5 |      TABLE ACCESS BY INDEX ROWID     | SWGL_DDJBXX              |    59 | 19234 |       |   506   (0)| 00:00:07 |
|*  6 |       INDEX RANGE SCAN               | IDX                      |  2370 |       |       |    12   (0)| 00:00:01 |
|   7 |      TABLE ACCESS BY INDEX ROWID     | SWGL_DDJBXX              |    10 |  3260 |       |    50   (0)| 00:00:01 |
|   8 |       BITMAP CONVERSION TO ROWIDS    |                          |       |       |       |         |             |
|   9 |        BITMAP AND                    |                          |       |       |       |         |             |
|  10 |         BITMAP CONVERSION FROM ROWIDS|                          |       |       |       |         |             |
|* 11 |          INDEX RANGE SCAN            | IDX                      |  2370 |       |       |    12   (0)| 00:00:01 |
|  12 |         BITMAP CONVERSION FROM ROWIDS|                          |       |       |       |         |             |
|* 13 |          INDEX RANGE SCAN            | IDX_SWGL_DDJBXX_KPRDM    |  2370 |       |       |    34   (0)| 00:00:01 |
|* 14 |      HASH JOIN RIGHT SEMI            |                          |  5926 |  2216K|       |  2423   (1)| 00:00:30 |
|  15 |       TABLE ACCESS BY INDEX ROWID    | KHGL_KHYWDLXX            | 10165 |   565K|       |  1916   (1)| 00:00:23 |
|* 16 |        INDEX RANGE SCAN              | IDX_KHGL_KHYWDLXX_SSKHJL | 10165 |       |       |   111   (0)| 00:00:02 |
|  17 |       TABLE ACCESS BY INDEX ROWID    | SWGL_DDJBXX              |  5926 |  1886K|       |   506   (0)| 00:00:07 |
|* 18 |        INDEX RANGE SCAN              | IDX                      |  2370 |       |       |    12   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------

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

   5 - filter("T"."LRR_DM"='e90e3fe4237c4af988477329c7f2059e')
   6 - access("T"."FZGS_DM"='001085' AND "T"."XJBZ"='9999' AND "T"."FROMNBGL1"='0')
  11 - access("T"."FZGS_DM"='001085' AND "T"."XJBZ"='9999' AND "T"."FROMNBGL1"='0')
       filter("T"."FROMNBGL1"='0' AND "T"."XJBZ"='9999' AND "T"."FZGS_DM"='001085')
  13 - access("T"."KPR_DM"='e90e3fe4237c4af988477329c7f2059e')
  14 - access("Y"."KH_ID"="T"."KH_ID")
  16 - access("Y"."SSKHJL_DM"='e90e3fe4237c4af988477329c7f2059e')
  18 - access("T"."FZGS_DM"='001085' AND "T"."XJBZ"='9999' AND "T"."FROMNBGL1"='0')


統計資訊
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      25628  consistent gets
          0  physical reads
          0  redo size
        512  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed


由於我不能直接連線到DB,這個SQL的優化就到此為止。