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

MySQL DISTINCT 與 COUNT(*) 深度解析:去重統計的正確姿勢與性能陷阱

     編輯:MySQL 資料庫相關知識

一、DISTINCT 核心用法

1. 計算不重複值個數

SELECT COUNT(DISTINCT id) FROM tablename;

2. 返回不重複值列表

SELECT DISTINCT id FROM tablename;

3. 多欄位去重陷阱

-- 實際行為:id 和 type 組合去重
SELECT DISTINCT id, type FROM tablename;
-- 等價於
SELECT id, type FROM tablename GROUP BY id, type;

誤區:以為只按 id 去重,實際是組合去重。

4. 解決方案:GROUP_CONCAT 輔助(MySQL 4.1+)

SELECT id, GROUP_CONCAT(DISTINCT type) FROM tablename GROUP BY id;

5. 替代方案:帶計數的去重

SELECT id, type, COUNT(DISTINCT id) FROM tablename GROUP BY id;
-- 或簡潔版
SELECT id, type FROM tablename GROUP BY id;

二、COUNT(*) 性能機制

1. 無 WHERE 極速返回

SELECT COUNT(*) FROM tablename;  -- MyISAM 瞬間返回,InnoDB 掃描但有優化

2. 有 WHERE 觸發全表掃描

SELECT COUNT(*) FROM tablename WHERE status=1;  -- 需逐行檢查

3. 存儲引擎差異

引擎無 WHERE有 WHERE原理
MyISAMO(1) 秒級全表掃描元數據存儲行數
InnoDB全表掃描(MVCC 一致性讀)全表掃描不存儲精確行數,需掃描聚簇索引

三、優化建議

  1. 近似值滿足業務:用 EXPLAIN SELECT COUNT(*) ... 觀察 rows 估算值
  2. 計數表模式:維護單獨統計表,觸發器/應用層同步更新
  3. 覆蓋索引:WHERE 條件欄位建立索引,利用 Using index 避免回表
  4. 分區表:按時間分區,查詢特定分區大幅減少掃描行數

四、實戰對比測試

-- 測試表
CREATE TABLE t_count (id INT PRIMARY KEY, val INT, KEY idx_val(val)) ENGINE=InnoDB;
-- 插入 100 萬測試數據...

-- 方案對比
SELECT COUNT(*) FROM t_count;                    -- 全表掃描 ~300ms
SELECT COUNT(*) FROM t_count WHERE val > 500000; -- 索引範圍掃描 ~50ms
SELECT COUNT(DISTINCT val) FROM t_count;         -- 去重統計 ~200ms

核心結論:InnoDB 下 COUNT(*) 無捷徑,善用 WHERE+索引與計數表模式;DISTINCT 多欄位時明確語義,優先考慮 GROUP BY 替代。

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