今天早上在做資料庫的安檢時候,發現乙個ora-01555錯誤:
這個sql語句明顯執行了很長時間而沒有完成。在觀察statspack報告中這個sql也在top
sql中占用了大量的db cache。物理讀很大。
下午做完其他的就打算優化一下這個sql
首先檢視這個sql的執行計畫
在pl/sql developer中的執行計畫視窗中執行這個sql然後得到執行計畫:如下
可以看到在巢狀查詢中使用了 提示 /*+ all_rows*/ (這個是我的錯,因為在上禮拜五的時候我發現一條同樣差不多的語句巢狀語句和另外一條語句是一模一樣的,我使用了這個 /*+ all_rows*/提示優化了一下,開發人員覺得第一張圖中中的語句也應該加上該提示,結果在今天這條語句出現了問題。)
person錶走的是索引全掃瞄這個效率有點兒低,但是更糟糕的是mailsend錶走的是全表掃瞄,根據語句中的條件
select * from mailsend ms wherems.personid=p.userid and (sysdate-15)<=ms.senddate and ms.mailid=1102
從執行計畫可以看出次查詢並沒有使用索引,在去到 dba_indexs 中查詢mailsend表是否有索引
select * from dba_indexs i where i.table_name=』mailsend』
果然沒有索引。
於是乎建立一條索引:
create index idx_perid_mailsend on mailsend(personid);
同時分析了一下該錶
analyzed table mailsend compute statistics;
改sql中還是用了 in 這個關鍵字,在查詢中最好將in使用exists替代來提高效能
修改後的sql如下:
在看一下執行計畫:
這個時候解決了mailsend表的全表掃瞄情況,但是person表最外層還是走的全表掃瞄(雖然內層走的是主鍵索引掃瞄)這才是很重要的原因,update因為要更新內層的結果集,所以走的是全表掃瞄,沒有使用索引,顯然是很慢的原因。
這個時候檢視person的相關索引,只有兩個復合索引。
這時候想起了可以使用提示強制走索引執行於是新增了乙個索引提示 /*+ index (tablename indexname) */(語法)
修改結果如下:
update /*+ index ( per index3_person) */ person per
set per.sort = nvl(per.sort, 0) + 1
where exists
(select userid
from (select
p.userid, p.email
from person p
where (sysdate - p.lastupdate) >=
(p.lastupdate + 3 - p.lastupdate)
and p.status = 3
and p.sort != 3
and not exists (select *
from mailsend ms
where ms.personid = p.userid
and (sysdate - 15) <= ms.senddate
and ms.mailid = 1102)) us where us.userid=per.userid)
再來看看執行計畫:
io耗費降低到66。
本文完。
Oracle Sql優化筆記
基本的sql編寫注意事項 需要注意的是,隨著oracle的公升級,查詢優化器會自動對sql語句進行優化,某些限制可能在新版本的oracle下不再是問題。尤其是採用cbo cost based optimization,基於代價的優化方式 時。我們可以總結一下可能引起全表掃瞄的操作 oracle優化器...
Oracle Sql優化筆記
基本的sql 編寫注意事項 需要注意的是,隨著oracle的公升級,查詢優化器會自 動對sql語句 進行優化,某些限制可能在新版本的oracle下不再是問題。尤其是採用 cbo cost based optimization 基於代價的 優化方式 時。我們可以 總結一下可能引起全表 掃瞄的操作 or...
Oracle Sql優化筆記
基本的sql編寫注意事項 需要注意的是,隨著oracle的公升級,查詢優化器會自動對sql語句進行優化,某些限制可能在新版本的oracle下不再是問題。尤其是採用cbo cost based optimization,基於代價的優化方式 時。我們可以總結一下可能引起全表掃瞄的操作 oracle優化器...