一次分頁查詢的優化

wei-xh發表於2012-03-14
SELECT a.ID,
       GMT_MODIFIED,
       GMT_CREATE,
       NAME,
       SOURCE,
       SIGN,
       CATEGORY_ID,
       DESCRIPTION,
       DETAILS,
       KEYWORDS,
       PIC_URLS,
       STATUS,
       KEY_VALUE1,
       KEY_VALUE2,
       KEY_VALUE3
  FROM (SELECT *
          FROM (SELECT id, rownum linenum
                  FROM (SELECT *
                          FROM (SELECT id
                                  FROM alibaba.SPU
                                 WHERE CATEGORY_ID = 1043726
                                   AND BITAND(Nvl(SIGN, 0), 1) = 1
                                 ORDER BY ID DESC)
                         WHERE rownum < 10001)
                 WHERE rownum <= 200)
         WHERE linenum >= 0) a,
       alibaba.spu b
 WHERE a.id = b.id;
同事問的一個問題,說這個SQL查詢很慢,該如何優化?
Index                          Column                          Col Column
Name                           Name                            Pos Details
------------------------------ ------------------------------ ---- ------------------------
SPU_CKKKSSGGNI_IND             CATEGORY_ID                       1 NUMBER(22)
                               KEY_VALUE1                        2 VARCHAR2(256)
                               KEY_VALUE2                        3 VARCHAR2(256)
                               KEY_VALUE3                        4 VARCHAR2(256)
                               STATUS                            5 VARCHAR2(16)
                               SIGN                              6 NUMBER(22)
                               GMT_CREATE                        7 DATE NOT NULL
                               GMT_MODIFIED                      8 DATE NOT NULL
                               NAME                              9 VARCHAR2(128)
                               ID                               10 NUMBER(22) NOT NULL
查詢謂詞出現了CATEGORY_ID,SIGN(函式).排序的條件是ID,ID也在索引裡。
由於SIGN上使用了函式,因此這個欄位只能在索引裡過濾。CATEGORY_ID = 1043726的值有非常多。
由於我們的查詢是分頁查詢,如果能在索引裡完成分頁,效率應該還是可以的。
可是遺憾的是,這個查詢並不能在索引裡完成分頁。
因為雖然ID包含在了索引裡,可是ID的前面還有很多其他的鍵值包含在索引裡。
對於(CATEGORY_ID,SIGN)為等值查詢的情況下,如果索引的組合為
(CATEGORY_ID,SIGN,ID),ID一定是有序的。
但是如果索引的組合是
(CATEGORY_ID,SIGN,XX,ID),那麼ID就不是有序的了。需要完全掃描相關索引排序後,再取出前TOP N條。
因此效率就差了。
解決的辦法很簡單,就是建立一個索引(CATEGORY_ID,SIGN,ID)就可以了。
還有就是同事說建立索引要對ID加上DESC關鍵字(CATEGORY_ID,SIGN,ID DESC),因為ORDER BY ID DESC.
其實這個是沒必要的,ORACLE可以完成這種轉換。執行計劃部分會出現INDEX RANGE SCAN DESCENDING的執行方式。

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

相關文章