如何優化in操作
今天開發人員讓我優化一個sql:
Select Item.*
From Item Item
Where Item.Item_Id in (15056, 14697);
這個item表很大,sql執行起來很慢。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12795 Card=2 Bytes=1
316)
1 0 TABLE ACCESS (FULL) OF 'ITEM' (Cost=12795 Card=2 Bytes=131
6)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
134234 consistent gets
26568 physical reads
2184 redo size
3336 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed
在這個例子中,item_id是item表的主鍵。這裡慢的原因是in操作不能用到索引,做全表掃描,但為什麼不能用索引呢?
實際上,oracle在處理in的時候是轉換成or進行處理的,如:
a in (1,2)相當於 a=1 or a=2
而對於b*tree索引來說,對於or操作是不會用到索引的。知道原因,下面就要找出解決方法了。
方法一、從b*tree索引著手
這種方法就是想辦法讓查詢可以走b*tree索引。要走btree索引,就要去掉or操作,所以把查詢改成一個等價的sql:
SQL> Select Item.* From Item Item Where Item.Item_Id in (14697)
2 union all
3 Select Item.* From Item Item Where Item.Item_Id in (15056);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=2 Bytes=1316)
1 0 UNION-ALL
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'ITEM' (Cost=3 Card=1 B
ytes=658)
3 2 INDEX (UNIQUE SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=2 Card
=1)
4 1 TABLE ACCESS (BY INDEX ROWID) OF 'ITEM' (Cost=3 Card=1 B
ytes=658)
5 4 INDEX (UNIQUE SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=2 Card
=1)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
3334 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed
從輸出結果可以看出,sql已經可以有索引了,效率也得到大幅提高。但這種辦法有缺陷:
如果in list的個數不確定,且如果in list較多的話,拼sql都是一個問題。我這個應用就是這種情況。
方法二、從點陣圖方式著手
我們知道,點陣圖索引是可以被or操作使用的,我們可以根據這一特點先用btree索引查詢資料,然後進行點陣圖轉換、聯合。
oracle給我們提供了一個hint來解決這個問題:use_concat。原sql修改為:
SQL> Select /*+ use_concat */ Item.* From Item Item Where Item.Item_Id in (15056,14697);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=2 Bytes=1316)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'ITEM' (Cost=6 Card=2 Byt
es=1316)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP OR
4 3 BITMAP CONVERSION (FROM ROWIDS)
5 4 INDEX (RANGE SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=2)
6 3 BITMAP CONVERSION (FROM ROWIDS)
7 6 INDEX (RANGE SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
3336 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed
從結果可以看到,oracle先通過主鍵索引分別對兩個id進行查詢,然後轉換成點陣圖進行合併,這樣效率就得到提供,對原sql的改動也很小,基本滿足了要求。
本文所有結果都是基於linux as 3+ oracle9204平臺。
這個轉換受_b_tree_bitmap_plans決定。如果該引數為true,則可進行轉換,否則不進行轉換。而8i裡,該引數預設為false,所以只有存在bitmap索引時才會考慮將B樹索引轉換為bitmap; 而到了9i裡,該引數預設為true了,則對任何索引都有可能進行bitmap轉換。
順便提一下,今天在itpub有帖子講到in能否用到btree索引問題,我這裡總結一下:
1、如果in list是具體的term,如id in (1,1,2)之類的話,是不會用到b*tree的
2、如果in list是有一個子查詢得到的,如id in (select id from t2),那麼這個查詢實際兩表關聯。那麼能否用到id列的索引要受到很多因素的制約了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/231499/viewspace-63760/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL優化基本操作MySql優化
- 優化寫磁碟操作優化
- windows10字型優化怎麼設定_windows10字型渲染優化如何操作Windows優化
- mysql常用的優化操作MySql優化
- JavaScript 操作DOM效能優化JavaScript優化
- win10優化硬碟加速怎麼操作_win10優化硬碟速度如何設定Win10優化硬碟
- 如何優化tableView優化View
- 如何優化WindowsOS使SQLServer效能最優化優化WindowsSQLServer
- SQL語句操作符優化SQL優化
- Spark效能優化:對RDD持久化或CheckPoint操作Spark優化持久化
- 如何優化程式效能優化
- 網站如何優化網站優化
- Swift如何優化效能?Swift優化
- 如何優化oracle pga優化Oracle
- win10系統如何優化記憶體_win10優化記憶體佔用率怎麼操作Win10優化記憶體
- 原始碼|String拼接操作”+”的優化?原始碼優化
- 對含distinct操作的SQL的優化SQL優化
- oracle update操作的優化一例Oracle優化
- 索引回表操作,ORACLE所作的優化索引Oracle優化
- 【案例】MySQL count操作優化案例一則MySql優化
- Java I/O 操作及優化建議Java優化
- SQL優化之操作符篇(zt)SQL優化
- 如何優化網頁轉化率?優化網頁
- win10優化磁碟使用技巧_win10磁碟優化怎麼操作Win10優化
- 如何優化氣泡排序?優化排序
- 如何優化這個sql?優化SQL
- 如何優雅地記錄操作日誌?
- 如何優雅地記錄操作日誌
- 如何優雅的記錄操作日誌?
- Linux操作文件——MySQL優化(5.7.26)LinuxMySql優化
- Java集合類操作優化經驗總結Java優化
- Android網路操作和優化相關Android優化
- 如何優化網頁轉化率?(上篇)優化網頁
- 如何優化網頁轉化率?(中篇)優化網頁
- 如何優化網頁轉化率?(下篇)優化網頁
- 如何進行頁面優化?優化
- 代理IP如何助力SEO優化?優化
- CRM如何優化企業流程?優化