MySQL的分頁語法比oracle簡單,直接limit就可以了,但是limit 1000000,10將掃描1000010的記錄並丟棄一百萬的數據,用戶翻頁獲得下10條記錄可能需要等待好幾分鐘。並且數據庫的IO資源在此期間受到很大的衝擊。
MariaDB提供了一種簡單的解決辦法,在檢查的數據行數大於指定值之後就報錯退出,節省數據庫IO資源。
我們先看看它的語法:
SELECT … FROM … WHERE … [group_clause] [order_clause] LIMIT [[offset,] row_count] ROWS EXAMINED rows_limit;
limit算是MySQL比oracle語法友好的一個非常方便的功能了。
但是,對於分頁查詢來說,如果你limit的offset非常大,那麼你的數據庫就悲劇了。
比如limit 1000000,10。那麼MySQL就需要先把1000010條記錄找出來,然後丟棄掉前100000條記錄。
查詢這麼多記錄數據庫是一個很大的負擔,並且查出來的100000條記錄其實也都不是你想要的數據。
這也是很多訪問量極大的網站取消了你直接跳到某頁功能的原因所在。
大部分的DBA對這個一籌莫展,部分DBA會說服產品設計師採用記錄上一頁最大ID,然後where id>? limit 10的辦法解決。
我們曾經遇到過在訂單庫上,很多limit 500000,10的並發使得數據庫響應時間變成原來的10倍的情況。導致了非常嚴重的故障。
MariaDB提供了一個變通的辦法,她讓你指定一個檢查行數限制。
如果超過這個檢查行數,那麼就不要浪費數據庫資源了,直接中斷查詢退出。
當然它並不是對所有的Query都有效,它的限制是:它對Delete和Update無效;
如果子查詢查詢的行操作,而你的限制是執行在父查詢上,那麼它只對父查詢有效;
如果是組合查詢(Union,子查詢等),在多個地方有ROWS EXAMINED檢查行限制,那麼只有最後一個限制有效。
當然,這個只是一個盡量減少對數據庫資源浪費的辦法,如果沒有必要,還是需要盡量從應用層面說服產品負責人避免這種訪問。
比如:
SELECT * from t1, t2 LIMIT 10 ROWS EXAMINED 10000;
這個查詢限制了檢查行數不能超過一萬。而下面這個查詢
SELECT * FROM t1
WHERE c1 IN (SELECT * FROM t2 WHERE c2 > ' ' LIMIT ROWS EXAMINED 0)
LIMIT ROWS EXAMINED 11;
內部的行數限制被覆蓋掉了,就只有外圍的11行檢查限制生效了。具體信息參考:http://kb.askmonty.org/en/limit-rows-examined/