利用分区优化SQL
一個哥們QQ問我,這個SQL怎么優化,它要跑160秒?SQL> explain plan for select a.so_region_code so_region_code,2 a.so_county_code so_county_code,3 a.so_org_id so_org_id,4 d.org_type_id org_type_id,5 a.op_id op_id,6 nvl(c.brand, 0) brand,7 e.res_code,8 a.busi_code,9 a.so_nbr,10 decode(a.isnormal,11 2,12 -count(distinct a.so_nbr),13 0,14 count(distinct a.so_nbr),15 0) so_amount,16 sum(decode(b.book_item_id, 23000002, item_total, 0)) / 100 sim_fee,17 sum(decode(b.book_item_id, 23000001, item_total, 0)) / 100 sim_fee_add,18 sum(decode(b.book_item_id, 27000003, item_total, 0)) / 100 sim_fee_discount,19 sum(decode(b.book_item_id, 21000013, 0, b.item_total)) / 100 total_fee20 from zk.cm_busi_201108 a,21 zk.cm_busi_charge_201108 b,22 zk.cm_user c,23 xg.sys_organizations d,24 zy.res_sim e25 where a.so_nbr = b.so_nbr(+)26 and a.serv_id = c.serv_id27 and c.sim_id = e.sim_id28 and a.so_org_id = d.org_id29 and (b.book_item_id in (23000001, 23000002, 27000003) or30 a.busi_code in (1,31 2,32 4,33 5,34 8,35 11,36 14,37 15,38 17,39 18,40 19,41 21,42 24,43 25,44 28,45 99,46 101,47 104,48 105,49 201,50 204,51 205,52 206,53 2201,54 1023,55 1006,56 3312,57 2251))58 and a.op_id != 7101026459 and a.so_date >= to_date('20110831000000', 'yyyymmddhh24miss')60 and a.so_date <= to_date('20110831235959', 'yyyymmddhh24miss')61 and a.so_county_code =711162 and a.so_nbr is not null63 group by a.so_region_code,64 a.so_county_code,65 a.so_org_id,66 d.org_type_id,67 a.op_id,68 c.brand,69 e.res_code,70 a.busi_code,71 a.so_nbr,72 a.isnormal;已解釋。已用時間: 00: 00: 00.03
SQL>
SQL> select * from table(dbms_xplan.display);PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Pstart| Pstop |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 59 | 11741 | 1703 (1)| | |
| 1 | SORT GROUP BY | | 59 | 11741 | 1703 (1)| | |
|* 2 | FILTER | | | | | | |
|* 3 | HASH JOIN OUTER | | | | | | |
| 4 | TABLE ACCESS BY LOCAL INDEX ROWID | RES_SIM | 1 | 26 | 32 (4)| | |
| 5 | NESTED LOOPS | | 46 | 7820 | 1670 (1)| | |
| 6 | NESTED LOOPS | | 49 | 7056 | 146 (2)| | |
| 7 | NESTED LOOPS | | 46 | 5244 | 53 (2)| | |
|* 8 | TABLE ACCESS BY INDEX ROWID | CM_BUSI_201108 | 46 | 4784 | 7 (15)| | |
|* 9 | INDEX RANGE SCAN | DX_BUSI_SO_DATE_201108 | 166K| | 3 (34)| | |
| 10 | TABLE ACCESS BY INDEX ROWID | SYS_ORGANIZATIONS | 1 | 10 | 2 (50)| | |
|* 11 | INDEX UNIQUE SCAN | PK_SYS_ORGANIZATIONS | 1 | | | | |
| 12 | TABLE ACCESS BY GLOBAL INDEX ROWID| CM_USER | 1 | 30 | 3 (34)| ROWID | ROW L |
|* 13 | INDEX UNIQUE SCAN | PK_ZK_CM_USER | 1 | | 2 (50)| | |
| 14 | PARTITION RANGE ALL | | | | | 1 | 10 |
|* 15 | INDEX RANGE SCAN | IDX_SIM_SIM | 1 | | 31 (4)| 1 | 10 |
| 16 | TABLE ACCESS FULL | CM_BUSI_CHARGE_201108 | 474 | 13746 | 32 (4)| | |
----------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("B"."BOOK_ITEM_ID"=23000001 OR "B"."BOOK_ITEM_ID"=23000002 OR "B"."BOOK_ITEM_ID"=27000"A"."BUSI_CODE"=1 OR "A"."BUSI_CODE"=2 OR "A"."BUSI_CODE"=4 OR "A"."BUSI_CODE"=5 OR "A"."BUSI"A"."BUSI_CODE"=11 OR "A"."BUSI_CODE"=14 OR "A"."BUSI_CODE"=15 OR "A"."BUSI_CODE"=17 OR "A".""A"."BUSI_CODE"=19 OR "A"."BUSI_CODE"=21 OR "A"."BUSI_CODE"=24 OR "A"."BUSI_CODE"=25 OR "A".""A"."BUSI_CODE"=99 OR "A"."BUSI_CODE"=101 OR "A"."BUSI_CODE"=104 OR "A"."BUSI_CODE"=105 OR "A"A"."BUSI_CODE"=204 OR "A"."BUSI_CODE"=205 OR "A"."BUSI_CODE"=206 OR "A"."BUSI_CODE"=1006 OR "A"."BUSI_CODE"=2201 OR "A"."BUSI_CODE"=2251 OR "A"."BUSI_CODE"=3312)3 - access("A"."SO_NBR"="B"."SO_NBR"(+))8 - filter("A"."SO_COUNTY_CODE"=7111 AND "A"."OP_ID"<>71010264 AND "A"."SO_NBR" IS NOT NULL)9 - access("A"."SO_DATE">=TO_DATE(' 2011-08-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "A"."SO_D2011-08-31 23:59:59', 'syyyy-mm-dd hh24:mi:ss'))11 - access("A"."SO_ORG_ID"="D"."ORG_ID")13 - access("A"."SERV_ID"="C"."SERV_ID")15 - access("C"."SIM_ID"="E"."SIM_ID")已選擇40行。已用時間: 00: 00: 00.20
CM_BUSI_201108 是大表,有3千多萬的數據,CM_USER也是一個大表,有3千多萬的數據 其他表都是小表
注意觀察第9行,CBO認為它返回166k的數據,回表的時候又過濾有filter過濾,這個時候CBO認為它返回46行,先不管這46行 CBO計算是對是錯,單單就是索引掃描返回166k到表
CM_BUSI_201108 去做166k次應該也很耗費時間。所以給出優化建議 對表CM_BUSI_201108進行分區,可以根據SO_DATE做range分區,另外SO_COUNTRY_CODE可以查看值多不多,如果不多可以做 range-list分區
他最終只做了range分區,并且讓他創建了一個本地有前綴的組合索引(他最開始創建的是global索引,沒有起到優化效果)
create index YI_XXX ON CM_BUSI_201108(SO_DATE,SO_COUNTRY_CODE) LOCAL
執行計劃如下:
-------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Pstart| Pstop | -------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 17 | 3264 | 635 (1)| | | | 1 | TABLE ACCESS BY LOCAL INDEX ROWID | RES_SIM | 1 | 26 | 32 (4)| | | | 2 | NESTED LOOPS | | 17 | 3264 | 635 (1)| | | | 3 | NESTED LOOPS | | 18 | 2988 | 75 (2)| | | |* 4 | FILTER | | | | | | | | 5 | NESTED LOOPS OUTER | | | | | | | | 6 | NESTED LOOPS | | 17 | 1870 | 24 (5)| | | |* 7 | TABLE ACCESS BY LOCAL INDEX ROWID| CM_BUSI_201108 | 17 | 1700 | 7 (15)| 6 | 6 | |* 8 | INDEX RANGE SCAN | YI_XXX | 61917 | | 3 (34)| 6 | 6 | | 9 | TABLE ACCESS BY INDEX ROWID | SYS_ORGANIZATIONS | 1 | 10 | 2 (50)| | | |* 10 | INDEX UNIQUE SCAN | PK_SYS_ORGANIZATIONS | 1 | | | | | |* 11 | INDEX RANGE SCAN | PK_CM_BUSI_CHARGE_201108 | 1 | 26 | 2 (50)| | | | 12 | TABLE ACCESS BY GLOBAL INDEX ROWID | CM_USER | 1 | 30 | 3 (34)| ROWID | ROW L | |* 13 | INDEX UNIQUE SCAN | PK_ZK_CM_USER | 1 | | 2 (50)| | | | 14 | PARTITION RANGE ALL | | | | | 1 | 10 | |* 15 | INDEX RANGE SCAN | IDX_SIM_SIM | 1 | | 31 (4)| 1 | 10 | --------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id): ---------------------------------------------------4 - filter("B"."BOOK_ITEM_ID"=23000001 OR "B"."BOOK_ITEM_ID"=23000002 OR "B"."BOOK_ITEM_ID"=27000003)7 - filter("A"."OP_ID"<>71010264)8 - access("A"."SO_DATE">=TO_DATE(' 2011-08-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "A"."SO_COUNTY_CODE"=7111 AND "A"."SO_DATE"<=TO_DATE(' 2011-08-31 23:59:59', 'syyyy-mm-dd hh24:mi:ss'))filter("A"."SO_COUNTY_CODE"=7111)10 - access("A"."SO_ORG_ID"="D"."ORG_ID")11 - access("A"."SO_NBR"="B"."SO_NBR"(+))13 - access("A"."SERV_ID"="C"."SERV_ID")15 - access("C"."SIM_ID"="E"."SIM_ID")
分區之后,需要過濾的數據量大大減少,這樣嵌套循環執行的次數也大大減少,最終SQL能在4秒左右跑完,其實這個優化方案并不是最優的,由于不能連接到他的數據庫,這個SQL的優化就暫時告一段落。分區對SQL的優化還是非常有幫助的。
轉載于:https://www.cnblogs.com/hehe520/archive/2011/09/20/6330563.html
總結
- 上一篇: C#汉字转换拼音技术详解(高性能)
- 下一篇: db2exc_971_WIN_x86,d