首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL GROUP BY 總行數獲取技巧:SQL_CALC_FOUND_ROWS 與 FOUND_ROWS() 組合拳

     編輯:MySQL 資料庫相關知識

問題場景

分頁查詢需同時返回:當頁資料 + 總符合行數(供前端計算總頁數)。傳統做法兩條查詢:


SELECT COUNT(*) FROM t WHERE cond;  -- 總數
SELECT * FROM t WHERE cond LIMIT 10, 20;  -- 分頁資料

MySQL 原生優化:SQL_CALC_FOUND_ROWS


SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE cond LIMIT 10, 20;
SELECT FOUND_ROWS();  -- 返回不帶 LIMIT 的總行數
  • 單次掃描完成兩個任務,避免重複評估 WHERE 條件
  • FOUND_ROWS() 必須緊跟在帶 SQL_CALC_FOUND_ROWS 的查詢之後

GROUP BY 場景適用


SELECT SQL_CALC_FOUND_ROWS t3.id, a, bunch, of, other, stuff
FROM t1, t2, t3
WHERE (associate t1,t2,and t3 with each other)
GROUP BY t3.id
LIMIT 10, 20;

SELECT FOUND_ROWS() AS total_groups;

返回分組後的總組數,而非原始行數。配合分頁顯示分組列表(如:按用戶分組的訂單統計)完美適用。

效能與避坑

  • 優點:減少一次全表/索引掃描,複雜 JOIN/GROUP BY 受益明顯
  • 缺點:MySQL 仍需掃描所有符合條件行才能算總數,大數據量下首次查詢慢
  • 8.0 棄用警告:SQL_CALC_FOUND_ROWS 標記棄用,未來版本移除

現代替代方案

1. 兩階段查詢 + 應用層快取(推薦)


-- 第一次查詢快取總數(Redis Key: total:cond_hash, TTL 30s)
SELECT COUNT(*) FROM t WHERE cond;

-- 後續分頁直接讀快取
SELECT * FROM t WHERE cond LIMIT 10, 20;

2. 估算總數(大數據量、近似可接受)


EXPLAIN SELECT * FROM t WHERE cond;
-- rows 欄位為優化器估算行數,極快但不精確

3. 觸發器/物化視圖維護精確計數


CREATE TABLE stats (cond_hash CHAR(32) PRIMARY KEY, total BIGINT, updated_at TIMESTAMP);
-- INSERT/UPDATE/DELETE 觸發器增減 total
-- 查詢總數變為單行點查,極快

4. COUNT(*) OVER() 窗口函數 (MySQL 8.0+)


SELECT *, COUNT(*) OVER() AS total
FROM t WHERE cond
LIMIT 10, 20;
-- 單次查詢返回資料+總數,但需掃描所有符合行計算窗口

GROUP BY 基礎用法補充


-- 簡單分組計數
SELECT column_id, COUNT(*) AS cnt FROM my_table GROUP BY column_id;

-- 多欄位分組
SELECT dept_id, status, COUNT(*) FROM emp GROUP BY dept_id, status;

-- 分組過濾
SELECT dept_id, AVG(sal) FROM emp GROUP BY dept_id HAVING AVG(sal) > 2000;

小結

SQL_CALC_FOUND_ROWS + FOUND_ROWS() 是 MySQL 經典分頁總數技巧,GROUP BY 同樣適用。但 8.0 棄用、大數據量效能一般,生產建議:快取 COUNT(*)、估算 rows、物化計數表、窗口函數 四選一視業務容忍度而定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved