關於分頁查詢的最佳化思路
目前在生產環境中有一個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/8494287/viewspace-1347014/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於分頁查詢的優化思路優化
- 關於批次分頁查詢
- 關於 groupBy 分組查詢的分頁處理
- 關於分頁查詢結果的快取問題快取
- 有關Oracle分頁查詢語句Oracle
- MySQL的分頁查詢MySql
- Oracle的分頁查詢Oracle
- Lucene的分頁查詢
- 關於資料字典的查詢效率最佳化
- Elasticsearch 分頁查詢Elasticsearch
- ssh 分頁查詢
- oracle分頁查詢Oracle
- MySQL全面瓦解9:查詢的排序、分頁相關MySql排序
- 分庫分表後的分頁查詢
- MySQL查詢中分頁思路的優化BFMySql優化
- 關於查詢最佳化的一些總結
- MySQL 百萬級資料量分頁查詢方法及其最佳化MySql
- MySQL分頁查詢offset過大,Sql最佳化經驗MySql
- ThinkPhp框架:分頁查詢PHP框架
- 分頁查詢優化優化
- NET 集合分頁查詢
- MySQL 多表查詢分頁MySql
- 分頁查詢重構
- Oracle分頁查詢格式Oracle
- 分散式任務排程內的 MySQL 分頁查詢最佳化分散式MySql
- SSH框架下的分頁查詢框架
- ssh框架中的分頁查詢框架
- 分頁查詢的排序問題排序
- pageHelper分頁外掛導致的查詢慢的問題最佳化
- 關於黑馬旅遊網的實現 --- 分頁查詢功能,點選分頁碼不顯示資料
- hibernate 通用分頁,查詢分頁的泛型類泛型
- Java中關於二分查詢的問題Java
- elasticsearch查詢之大資料集分頁查詢Elasticsearch大資料
- MySQL 如何最佳化大分頁查詢?MySql
- 關於 MyBatis-Plus 分頁查詢的探討 → count 都為 0 了,為什麼還要查詢記錄?MyBatis
- indexdb實現分頁查詢Index
- AntDesignBlazor示例——分頁查詢Blazor
- MySQL分頁查詢優化MySql優化