Web 應用常需分頁顯示。早期做法:一次性查出所有行交由前端控件分頁,導致資料庫壓力大、網絡傳輸量大、用戶體驗差。
SELECT * FROM (
SELECT a.*, ROWNUM rnum FROM (
SELECT * FROM yz_bingrenyz
) a WHERE ROWNUM <= 5300
) WHERE rnum >= 5000;
原理:內層查出前 5300 行,外層丟棄前 5000 行。隨頁碼增大,掃描行數線性增長,性能急劇下降。
SELECT * FROM (
SELECT * FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY NULL) AS row_number
FROM yz_bingrenyz t
) p WHERE p.row_number > 5000
) q WHERE ROWNUM <= 30;
ROW_NUMBER() OVER (ORDER BY NULL) 為每行分配唯一序號,無排序開銷。row_number > 5000,再取前 30 行,實現「精準定位 + 少量取數」。| 方案 | 耗時 | 執行計劃特徵 |
|---|---|---|
| ROWNUM 子查詢 | 1.3 s | 全表掃描 + COUNT STOPKEY 後過濾 |
| ROW_NUMBER() | 0.25 s | WINDOW SORT + FILTER 提前裁剪 |
性能提升 5 倍以上,且隨頁碼增長優勢擴大。
DbCommand 動態拼接表名、主鍵、頁碼、頁大小)。Skip()/Take(),EF 會自動生成類似 ROW_NUMBER() 的高效 SQL。棄用「先取後丟」的 ROWNUM 子查詢,改用 ROW_NUMBER() 分析函數配合外層 ROWNUM 截斷,是 Oracle 高效分頁的標準最佳實踐。