sql優化一例(index_desc)

Tomthe發表於2011-06-25

在生產庫看到這樣一條sql,沒有走索引。

10:26:05 SQL> EXPLAIN plan FOR
10:27:06 2 SELECT thread_id
10:27:06 3 FROM (SELECT thread_id, rownum rn
10:27:06 4 FROM (SELECT b.thread_id
10:27:06 5 FROM test_blog b
10:27:06 6 WHERE b.STATUS != -1
10:27:06 7 ORDER BY b.gmt_modified DESC)
10:27:06 8 WHERE rownum <= :1)
10:27:06 9 WHERE rn >= :2;
 
PLAN_TABLE_OUTPUT
---------------------------------
 
-------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost |
-------------------------------------------
| 0 | SELECT STATEMENT | | 1429K| 35M| | 6123 |
|* 1 | VIEW | | 1429K| 35M| | 6123 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 1429K| 17M| | 6123 |
|* 4 | SORT ORDER BY STOPKEY| | 1429K| 23M| 76M| 6123 |
|* 5 | TABLE ACCESS FULL | TEST_BLOG | 1429K| 23M| | 798 |
-----------------------------------

在status、gmt_modified、thread_id上有個組合索引IDX_BLOG_STATUS,大家都知道”不等於”是不會用到index,分析了一下業務,完全可以把status != -1改為status = 0,這裡我還多考慮了一步,加個hint,固定它走IDX_BLOG_STATUS。

看一下加hint後的執行計劃,感覺沒有什麼大的問題

10:34:04 SQL> EXPLAIN plan FOR
10:34:20 2 SELECT thread_id
10:34:20 3 FROM (SELECT /*+ index(b IDX_BLOG_STATUS) */thread_id, rownum rn
10:34:20 4 FROM (SELECT b.thread_id
10:34:20 5 FROM test_blog b
10:34:20 6 WHERE b.STATUS = 0
10:34:20 7 ORDER BY b.gmt_modified DESC)
10:34:20 8 WHERE rownum <= 500)
10:34:20 9 WHERE rn >= 450;
 
Explained.
 
Elapsed: 00:00:00.00
10:34:21 SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
----------------------------------------------
 
----------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------
| 0 | SELECT STATEMENT | | 500 | 13000 | 5174 |
|* 1 | VIEW | | 500 | 13000 | 5174 |
|* 2 | COUNT STOPKEY | | | | |
| 3 | VIEW | | 1429K| 17M| 5174 |
|* 4 | INDEX RANGE SCAN DESCENDING| IDX_BLOG_STATUS | 1429K| 23M| 12935 |
----------------------------------------------------
 
Predicate Information (IDENTIFIED BY operation id):
--------------------------
 
1 - filter("from$_subquery$_001"."RN">=450)
2 - filter(ROWNUM<=500)
4 - access("B"."STATUS"=0)
 
Note: cpu costing IS off
 
19 rows selected.
 
Elapsed: 00:00:00.08
10:34:25 SQL> SET autot traceonly
10:35:33 SQL> SELECT thread_id
10:35:35 2 FROM (SELECT thread_id, rownum rn
10:35:35 3 FROM (SELECT /*+index( b IDX_BLOG_STATUS)*/b.thread_id
10:35:35 4 FROM test_blog b
10:35:35 5 WHERE b.STATUS =0
10:35:35 6 ORDER BY b.gmt_modified DESC)
10:35:35 7 WHERE rownum <= 500)
10:35:35 8 WHERE rn >= 450;
 
51 rows selected.
 
Elapsed: 00:00:52.97
 
Execution Plan
----------------------------------------
SELECT STATEMENT Optimizer=CHOOSE (Cost=10499 Card=500 Bytes=13000)
0 VIEW (Cost=10499 Card=500 Bytes=13000)
1 COUNT (STOPKEY)
2 VIEW (Cost=10499 Card=1429964 Bytes=18589532)
3 SORT (ORDER BY STOPKEY) (Cost=10499 Card=1429964 Bytes=24309388) 
4 INDEX(RANGE SCAN) OF 'IDX_BLOG_STATUS' (NON-UNIQUE)(Cost=12935Card=1429964Bytes=24309388) 
 
Statistics
------------------------------
0 recursive calls
0 db block gets
43836 consistent gets
43058 physical reads
7988 redo size
1530 bytes sent via SQL*Net TO client
689 bytes received via SQL*Net FROM client
5 SQL*Net roundtrips TO/FROM client
1 sorts (memory)
0 sorts (disk)
51 rows processed
 
實際走得就有問題了,多了個sort

hint加得有點問題,改成/*+ index_desc( b IDX_BLOG_STATUS) */,因為都能在索引中完成(包括sort),不用回表。

10:47:18 SQL> SELECT thread_id
10:47:19 2 FROM (SELECT thread_id, rownum rn
10:47:19 3 FROM (SELECT /*+index_desc( b IDX_BLOG_STATUS)*/b.thread_id
10:47:19 4 FROM test_blog b
10:47:19 5 WHERE b.STATUS =0
10:47:19 6 ORDER BY b.gmt_modified DESC)
10:47:19 7 WHERE rownum <= 500)
10:47:19 8 WHERE rn >= 450;
 
51 rows selected.
 
Elapsed: 00:00:06.81
 
Execution Plan
------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=5174 Card=500 Bytes=13000)
1 0 VIEW (Cost=5174 Card=500 Bytes=13000)
2 1 COUNT (STOPKEY)
3 2 VIEW (Cost=5174 Card=1429964 Bytes=18589532)
4 3 INDEX (RANGE SCAN DESCENDING) OF 'IDX_BLOG_STATUS' (NON-UNIQUE)
 (Cost=12935 Card=1429964 Bytes=24309388)
 
Statistics
-----------------------------------
0 recursive calls
0 db block gets
10 consistent gets
0 physical reads
0 redo size
1529 bytes sent via SQL*Net TO client
689 bytes received via SQL*Net FROM client
5 SQL*Net roundtrips TO/FROM client
0 sorts (memory)
0 sorts (disk)
51 rows processed

邏輯讀從43836下降到10個。
總結:explain plan也不可信呀,關鍵還是要看實際跑得怎麼樣!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/20577218/viewspace-700740/,如需轉載,請註明出處,否則將追究法律責任。

相關文章