在日常数据库开发中,COUNT 查询可能是最常见的操作之一。然而,面对 COUNT(1)、COUNT(*)、COUNT(列) 这些看似相似的写法,很多开发者往往会感到困惑:它们之间到底有什么区别?哪种方式性能更好?
– 在以下场景中,COUNT的性能至关重要:
深入理解
实践指导
性能提升
COUNT(*) = COUNT(1) > COUNT(主键) > COUNT(普通索引列) > COUNT(未索引列)
- 创建测试表
CREATE TABLE user (
id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT,
INDEX idx_name(name)
);
- 插入测试数据
INSERT INTO user ...
- 性能测试
SELECT COUNT(1) FROM user; -- 0.5s
SELECT COUNT(*) FROM user; -- 0.5s
SELECT COUNT(id) FROM user; -- 0.6s
SELECT COUNT(name) FROM user; -- 0.8s
SELECT COUNT(age) FROM user; -- 1.2s
- COUNT(1)
SELECT COUNT(1) FROM user;
MySQL优化器会选择最小的索引树来遍历
不需要取出字段值
- COUNT(*)
SELECT COUNT(*) FROM user;
与COUNT(1)实现原理相同
MySQL特殊优化,不会取出任何字段值
SELECT COUNT(id) FROM user;
需要取出主键值
然后判断是否为NULL
性能略低于COUNT(1)和COUNT(*)
SELECT COUNT(name) FROM user;
优化器会选择最小的索引树
需要取出索引列的值
然后判断是否为NULL
SELECT COUNT(age) FROM user;
需要全表扫描
取出字段值判断NULL
性能最差
-- 插入测试数据
INSERT INTO user VALUES
(1, 'Tom', NULL),
(2, NULL, 20),
(3, 'Jerry', 25);
测试结果
SELECT COUNT(*) FROM user; -- 结果:3
SELECT COUNT(1) FROM user; -- 结果:3
SELECT COUNT(name) FROM user; -- 结果:2
SELECT COUNT(age) FROM user; -- 结果:2
COUNT(*) 和 COUNT(1):不会忽略NULL值
COUNT(列名):会忽略NULL值
MyISAM
- 存储了表的行数
- COUNT(*)直接返回该值
- 性能极快
InnoDB
- 不存储表的行数
- 需要扫描表或索引
- 性能相对较慢
-- 1. 使用近似值
SELECT COUNT(*) FROM user;
-改为
EXPLAIN SELECT COUNT(*) FROM user;
- 查看预估行数
- 2. 使用缓存
- 在应用层缓存计数
- 定期更新
- 3. 使用汇总表
CREATE TABLE user_count (
count INT,
update_time TIMESTAMP
);
- 优化前
SELECT type, COUNT(*)
FROM orders
GROUP BY type;
- 优化后(使用索引)
ALTER TABLE orders ADD INDEX idx_type(type);
- 或使用汇总表
CREATE TABLE order_summary (
type VARCHAR(50),
count INT,
update_time TIMESTAMP
);
- 推荐使用
SELECT COUNT(*) FROM user;
- 或
SELECT COUNT(1) FROM user;
- 统计有效用户数
SELECT COUNT(name) FROM user;
-- name为NOT NULL字段
- 统计有年龄的用户
SELECT COUNT(age) FROM user;
-- age允许为NULL
- 按状态统计订单数
SELECT status, COUNT(*)
FROM orders
GROUP BY status;
- 统计各年龄段用户数
SELECT
CASE
WHEN age < 20 THEN '青少年'
WHEN age < 30 THEN '青年'
ELSE '成年'
END as age_group,
COUNT(1)
FROM user
GROUP BY age_group;
- 避免在大表上使用COUNT(未索引列)
- 避免使用COUNT(DISTINCT column)
- 避免在事务中执行COUNT查询
- 1. 优先使用COUNT(*)
- 2. 需要统计非NULL值时使用COUNT(列名)
- 3. 大数据量时考虑使用汇总表或缓存
- 4. 添加合适的索引
- 监控慢查询
SHOW VARIABLES LIKE '%slow_query%';
SHOW VARIABLES LIKE '%long_query_time%';
- 分析执行计划
EXPLAIN SELECT COUNT(*) FROM user;
COUNT(*) = COUNT(1) > COUNT(主键) > COUNT(普通索引列) > COUNT(未索引列)
- 推荐使用
SELECT COUNT(*) FROM table;
- 避免使用
SELECT COUNT(non_indexed_column) FROM table;
架构设计
性能监控
分库分表场景
高并发环境
大数据量处理
选择建议
注意事项
优化思路