我們進行SQL優化時,常常會碰到對大量數據集進行排序,然后從排序后的集合取前部份結果的需求,這類情況下,當我們依照常規思路去寫SQL時,系統會先讀取過濾取得所有集合,然落后行排序,再從排序結果取出極少許結果,這個進程中,大量數據的掃描讀取、過濾、排序會消耗掉大量的系統資源,SQL性能也會存在很大的問題,實踐中,幾分鐘乃至幾個小時不出結果的情況很常見。為了優化這類場景的SQL,我們常常會讓查詢順序掃描建在排序列上的索引,已避開大量的數據讀取和排序。
但實踐中發現,當索引列不在條件中出現時,ORACLE不會產生掃描索引的計劃,即便用hint也不能讓查詢沿著目的索引掃描,例如:
create table t1(c1 int,c2 char(10));
create index idx1_t1 on t1(c1);
select * from (
select * from t1 order by c1)
where rownum<6;
很明顯,這類寫法會致使先讀取表,再進行排序,然后取前5條記錄,計劃以下:
如果我們這么寫,語義是1樣的,但會省去了大量的讀取和排序代價:
select /*+ index(t1,idx1_t1)*/* from t1 where rownum<6;
該SQL的履行計劃以下:
大家可以看到,該SQL并沒依照hint唆使,順序掃描idx1_t1索引,這是為何呢?個人猜想,多是Oracle優化器認為過濾條件內沒c1列,走索引比走FTS效力更低,所以,干脆就不斟酌走索引這類計劃,即便用hint也要疏忽,這點感覺有點不盡人意。那末,我們想甚么辦法才能讓優化器選擇掃描idx1_t1的計劃呢?我們只需要在where中加個c1列上的條件就能夠了,例如:
select /*+ index(t1,idx1_t1)*/* from t1 where rownum<6 and c1<>⑴;
這么修改后的計劃以下:
因而可知,我們優化類似場景時,只需滿足兩點:
1、排序列上存在索引;
2、where條件中有該索引列上的條件;
如果能實現依照索引掃描,性能有不計其數倍的提升也是非??赡艿?,這點在實踐中得到了驗證。
上一篇 程序休眠問題的C代碼實現
下一篇 圖像處理基礎知識像素高寬分辨率