在分頁查詢中,GROUP BY 聚合後若需同時獲取總分組數與當頁數據,傳統做法需執行兩條 SQL:一條 COUNT(*) 統計總數,一條 LIMIT 取數據。這不僅增加資料庫負載,還可能導致主從延遲下的數據不一致。
MySQL 內建 SQL_CALC_FOUND_ROWS 提示優化器計算無 LIMIT 時的總行數,隨後調用 FOUND_ROWS() 即可獲取該值,僅需一次查詢往返。
-- 傳統兩次查詢
SELECT COUNT(*) FROM `table` WHERE ...;
SELECT * FROM `table` WHERE ... LIMIT 10, 20;
-- 優化後:單次往返
SELECT SQL_CALC_FOUND_ROWS * FROM `table` WHERE ... LIMIT 10, 20;
SELECT FOUND_ROWS() AS total_count;
SELECT SQL_CALC_FOUND_ROWS
t3.id, a, bunch, of, other, stuff
FROM t1, t2, t3
WHERE (關聯條件)
GROUP BY t3.id
LIMIT 10, 20;
SELECT FOUND_ROWS() AS total_groups;
-- 統計每個 column_id 出現次數
SELECT column_id, COUNT(*) AS cnt
FROM my_table
GROUP BY column_id;
SQL_CALC_FOUND_ROWS 在 8.0.17 標記為棄用,未來版本可能移除。新專案建議改用窗口函數 COUNT(*) OVER() 或兩條獨立查詢。REPEATABLE READ 下兩次查詢結果一致,READ COMMITTED 可能出現幻讀導致總數與數據不符。-- 使用窗口函數一次查詢獲取總數與分頁數據
SELECT *, COUNT(*) OVER() AS total_count
FROM (
SELECT t3.id, ...
FROM t1, t2, t3
WHERE ...
GROUP BY t3.id
) AS sub
LIMIT 10, 20;
根據 MySQL 版本與業務量級選擇適合方案,SQL_CALC_FOUND_ROWS 仍是 5.7/早期 8.0 版本的實用技巧。