關於分頁查詢的優化思路
目前在生產環境中有一個sql語句執行時間長達7分鐘,而且執行頻率極高。
其中PROC_INST中有將近6千萬的資料。其中STEP_INST是一個物化檢視,裡面還有5千多條資料。
可以看到這個語句已經有了一些調優的痕跡,可以從裡面的子查詢和hint能夠看出一些資訊。
SELECT PROC_INST.OBJID, PROC_INST.CREATION_TIME
FROM PROC_INST,
(SELECT / * +leading(PROC_INST LIST table_bpm_step_inst)
FULL(PROC_INST) hash_aj(LIST) use_nl(table_bpm_step_inst) * /
PROC_INST.OBJID, PROC_INST.CREATION_TIME, ROW_NUMBER() OVER(ORDER BY creation_time) rn
FROM PROC_INST,
(SELECT / * +materialize
FULL(in_step) PARALLEL(in_step, 8) * / in_step.root2proc_inst
FROM STEP_INST in_step
WHERE in_step.status NOT IN (?,)
OR in_step.WAIT_TIME IS NOT NULL) LIST,
STEP_INST
WHERE STEP_INST.ROOT2PROC_INST =
PROC_INST.OBJID
AND PROC_INST.ROOT_STATUS = ?
AND PROC_INST.STATUS = ?
AND STEP_INST.OBJID =
PROC_INST.BEGIN2STEP_INST
AND STEP_INST.COMMITTER = ?
AND STEP_INST.STATUS IN (?,)
AND STEP_INST.WAIT_TIME IS NULL
AND STEP_INST.ASSIGNEE = ?
AND PROC_INST.OBJID = list.root2proc_inst(+)
AND list.root2proc_inst IS NULL
ORDER BY CREATION_TIME) INNER_QRY
WHERE INNER_QRY.OBJID = PROC_INST.OBJID
AND INNER_QRY.rn > ?
AND INNER_QRY.rn < ?
上面的查詢有幾個地方需要注意
首先是分析函式row_number的使用。其實在大量的資料查詢中直接使用rownum要高效一些,而且在子查詢的結果又加了一層order by的排序操作,所以可以考慮去除row_number()
關於AND list.root2proc_inst IS NULL的查詢條件,如果看得仔細一點就會發現,這個過濾條件完全可以放在子查詢list裡面,儘可能排除較多的資料。
子查詢的輸出結果集PROC_INST.OBJID, PROC_INST.CREATION_TIME,可以考慮直接使用rowid來代替對應的欄位值,這樣可能對於索引來說就可以是的索引的使用更加高效,如果是range scan就可以從某種程度上提升為fast scan.
最後的這個地方看似沒有問題,其實是最需要做改進的地方。如果輸出1000~2000行的資料,那麼子查詢就會先得查出2000條資料。
AND INNER_QRY.rn > ?
AND INNER_QRY.rn < ?
如果輸出100000~101000 這樣的話,就得先得到101000行的資料,然後再排除過濾。這樣的話每個查詢的執行代價都會不同,可以考慮在回表的資料上進行一個統一的規劃。
基本思路就是先在order by之後的子查詢之後做一個rownum 然後只輸出rowid。再上一層的子查詢中繼續拍段rownum>? 這樣基於rowid的排除更加清晰。
改進之後的sql語句類似下面的樣子。
SELECT PROC_INST.OBJID, PROC_INST.CREATION_TIME
FROM PROC_INST where rid in (
(SELECT / * +leading(PROC_INST LIST table_bpm_step_inst)
FULL(PROC_INST) hash_aj(LIST) use_nl(table_bpm_step_inst) * /
rid
FROM
(select rowid rid,rownum rn from
(select PROC_INST.rowid from
PROC_INST,
(SELECT / * +materialize
FULL(in_step) PARALLEL(in_step, 8) * / in_step.root2proc_inst
FROM STEP_INST in_step
WHERE in_step.status NOT IN (?,)
OR in_step.WAIT_TIME IS NOT NULL
AND list.root2proc_inst IS NULL) LIST,
STEP_INST
WHERE STEP_INST.ROOT2PROC_INST =
PROC_INST.OBJID
AND PROC_INST.ROOT_STATUS = ?
AND PROC_INST.STATUS = ?
AND STEP_INST.OBJID =
PROC_INST.BEGIN2STEP_INST
AND STEP_INST.COMMITTER = ?
AND STEP_INST.STATUS IN (?,)
AND STEP_INST.WAIT_TIME IS NULL
AND STEP_INST.ASSIGNEE = ?
AND PROC_INST.OBJID = list.root2proc_inst(+)
ORDER BY CREATION_TIME) INNER_QRY
where rownum)
AND INNER_QRY.rn >= ?)
最後優化的結果稍後奉上。
其中PROC_INST中有將近6千萬的資料。其中STEP_INST是一個物化檢視,裡面還有5千多條資料。
可以看到這個語句已經有了一些調優的痕跡,可以從裡面的子查詢和hint能夠看出一些資訊。
SELECT PROC_INST.OBJID, PROC_INST.CREATION_TIME
FROM PROC_INST,
(SELECT / * +leading(PROC_INST LIST table_bpm_step_inst)
FULL(PROC_INST) hash_aj(LIST) use_nl(table_bpm_step_inst) * /
PROC_INST.OBJID, PROC_INST.CREATION_TIME, ROW_NUMBER() OVER(ORDER BY creation_time) rn
FROM PROC_INST,
(SELECT / * +materialize
FULL(in_step) PARALLEL(in_step, 8) * / in_step.root2proc_inst
FROM STEP_INST in_step
WHERE in_step.status NOT IN (?,)
OR in_step.WAIT_TIME IS NOT NULL) LIST,
STEP_INST
WHERE STEP_INST.ROOT2PROC_INST =
PROC_INST.OBJID
AND PROC_INST.ROOT_STATUS = ?
AND PROC_INST.STATUS = ?
AND STEP_INST.OBJID =
PROC_INST.BEGIN2STEP_INST
AND STEP_INST.COMMITTER = ?
AND STEP_INST.STATUS IN (?,)
AND STEP_INST.WAIT_TIME IS NULL
AND STEP_INST.ASSIGNEE = ?
AND PROC_INST.OBJID = list.root2proc_inst(+)
AND list.root2proc_inst IS NULL
ORDER BY CREATION_TIME) INNER_QRY
WHERE INNER_QRY.OBJID = PROC_INST.OBJID
AND INNER_QRY.rn > ?
AND INNER_QRY.rn < ?
上面的查詢有幾個地方需要注意
首先是分析函式row_number的使用。其實在大量的資料查詢中直接使用rownum要高效一些,而且在子查詢的結果又加了一層order by的排序操作,所以可以考慮去除row_number()
關於AND list.root2proc_inst IS NULL的查詢條件,如果看得仔細一點就會發現,這個過濾條件完全可以放在子查詢list裡面,儘可能排除較多的資料。
子查詢的輸出結果集PROC_INST.OBJID, PROC_INST.CREATION_TIME,可以考慮直接使用rowid來代替對應的欄位值,這樣可能對於索引來說就可以是的索引的使用更加高效,如果是range scan就可以從某種程度上提升為fast scan.
最後的這個地方看似沒有問題,其實是最需要做改進的地方。如果輸出1000~2000行的資料,那麼子查詢就會先得查出2000條資料。
AND INNER_QRY.rn > ?
AND INNER_QRY.rn < ?
如果輸出100000~101000 這樣的話,就得先得到101000行的資料,然後再排除過濾。這樣的話每個查詢的執行代價都會不同,可以考慮在回表的資料上進行一個統一的規劃。
基本思路就是先在order by之後的子查詢之後做一個rownum 然後只輸出rowid。再上一層的子查詢中繼續拍段rownum>? 這樣基於rowid的排除更加清晰。
改進之後的sql語句類似下面的樣子。
SELECT PROC_INST.OBJID, PROC_INST.CREATION_TIME
FROM PROC_INST where rid in (
(SELECT / * +leading(PROC_INST LIST table_bpm_step_inst)
FULL(PROC_INST) hash_aj(LIST) use_nl(table_bpm_step_inst) * /
rid
FROM
(select rowid rid,rownum rn from
(select PROC_INST.rowid from
PROC_INST,
(SELECT / * +materialize
FULL(in_step) PARALLEL(in_step, 8) * / in_step.root2proc_inst
FROM STEP_INST in_step
WHERE in_step.status NOT IN (?,)
OR in_step.WAIT_TIME IS NOT NULL
AND list.root2proc_inst IS NULL) LIST,
STEP_INST
WHERE STEP_INST.ROOT2PROC_INST =
PROC_INST.OBJID
AND PROC_INST.ROOT_STATUS = ?
AND PROC_INST.STATUS = ?
AND STEP_INST.OBJID =
PROC_INST.BEGIN2STEP_INST
AND STEP_INST.COMMITTER = ?
AND STEP_INST.STATUS IN (?,)
AND STEP_INST.WAIT_TIME IS NULL
AND STEP_INST.ASSIGNEE = ?
AND PROC_INST.OBJID = list.root2proc_inst(+)
ORDER BY CREATION_TIME) INNER_QRY
where rownum)
AND INNER_QRY.rn >= ?)
最後優化的結果稍後奉上。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1282223/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 分頁查詢優化優化
- MySQL查詢中分頁思路的優化BFMySql優化
- MySQL分頁查詢優化MySql優化
- MySQL——優化巢狀查詢和分頁查詢MySql優化巢狀
- MySQL分優化之超大頁查詢MySql優化
- 關於 groupBy 分組查詢的分頁處理
- 資料庫全表查詢之-分頁查詢優化資料庫優化
- 關於樹結構的查詢優化,及許可權樹的查詢優化優化
- 效能優化之分頁查詢優化
- 資料量很大,分頁查詢很慢,該怎麼優化?優化
- Oracle:優化方法總結(關於連表查詢)Oracle優化
- MySQL的分頁查詢MySql
- 如何優雅地實現分頁查詢
- Elasticsearch 分頁查詢Elasticsearch
- MySQL全面瓦解9:查詢的排序、分頁相關MySql排序
- 分庫分表後的分頁查詢
- 海量資料庫的查詢優化及分頁演算法方案(轉)資料庫優化演算法
- 關於 SAP Spartacus CmsService.getComponentData 可能的優化思路優化
- 查詢優化優化
- NET 集合分頁查詢
- AntDesignBlazor示例——分頁查詢Blazor
- ThinkPhp框架:分頁查詢PHP框架
- MySQL 的查詢優化MySql優化
- SSH框架下的分頁查詢框架
- MySQL 千萬資料庫深分頁查詢優化,拒絕線上故障!MySql資料庫優化
- 關於黑馬旅遊網的實現 --- 分頁查詢功能,點選分頁碼不顯示資料
- elasticsearch查詢之大資料集分頁查詢Elasticsearch大資料
- Java中關於二分查詢的問題Java
- 關於 MyBatis-Plus 分頁查詢的探討 → count 都為 0 了,為什麼還要查詢記錄?MyBatis
- sharding-jdbc分表場景下的分頁查詢最佳化JDBC
- pgsql查詢優化之模糊查詢SQL優化
- indexdb實現分頁查詢Index
- HBase查詢優化優化
- Oracle in 查詢優化Oracle優化
- join 查詢優化優化
- MySQL查詢優化MySql優化
- Oracle總結【SQL細節、多表查詢、分組查詢、分頁】OracleSQL
- MySQL鎖表相關問題查詢思路MySql
- 記一次關於Laravel model查詢返回大量資料的效能優化Laravel優化