当前位置: 首页 > news >正文

、SEATA分布式事务——XA模式奖

MySQL 中的 count 三兄弟:效率大比拼!

一、快速结论(先看结论再看分析)

方式 作用 效率 一句话总结

count(*) 统计所有行数 最高 我是专业的!我为统计而生

count(1) 统计所有行数 同样高效 我是 count(*) 的马甲兄弟

count(列名) 统计该列非 NULL 的行数 ? 较慢 我挑剔,我只数非空值

结论:用 count(*) 就对了! ?

二、代码示例:亲测三兄弟的差别

准备测试数据

-- 创建测试表

CREATE TABLE user_test (

id INT PRIMARY KEY AUTO_INCREMENT,

name VARCHAR(50),

age INT,

email VARCHAR(100)

);

-- 插入测试数据(故意插入一些NULL值)

INSERT INTO user_test (name, age, email) VALUES

('张三', 25, 'zhangsan@example.com'),

('李四', NULL, NULL),

('王五', 30, 'wangwu@example.com'),

(NULL, 28, 'unknown@example.com'),

('赵六', 35, NULL);

测试查询

-- 查看表中的数据

SELECT * FROM user_test;

/*

+----+--------+------+--------------------+

| id | name | age | email |

+----+--------+------+--------------------+

| 1 | 张三 | 25 | zhangsan@example...|

| 2 | 李四 | NULL | NULL |

| 3 | 王五 | 30 | wangwu@example.com |

| 4 | NULL | 28 | unknown@example.com|

| 5 | 赵六 | 35 | NULL |

+----+--------+------+--------------------+

*/

-- 测试1:count(*) 统计所有行数

SELECT count(*) FROM user_test; -- 结果:5 ?

-- 翻译:"老板,我有多少行数据?全都要!"

-- 测试2:count(1) 统计所有行数

SELECT count(1) FROM user_test; -- 结果:5 ?

-- 翻译:"老板,你给我个固定值1,我数有多少个1"

-- 测试3:count(列名) 统计非NULL的行数

SELECT count(name) FROM user_test; -- 结果:4 ?(NULL的那行没算)

SELECT count(age) FROM user_test; -- 结果:4 ?(NULL的那行没算)

SELECT count(email) FROM user_test; -- 结果:3 ?(两个NULL都没算)

-- 翻译:"我只数有身份证的人,黑户不算"

三、深入剖析:它们到底有啥不同?

1. 语义区别(最重要的区别!)

-- count(*) 是 SQL 标准写法

-- 意思:给我这个表有多少行数据

-- 相当于:"这个会议室有多少个座位?"

-- count(1) 是 count(*) 的一种写法

-- 意思:统计有多少个1

-- 相当于:"给每个座位发个苹果,最后数苹果"

-- count(列名) 是统计该列非NULL值的数量

-- 意思:这个会议室有多少人带了手机

-- 相当于:"检查每个座位,如果有人带了手机就计数"

2. 性能区别(神话与现实)

传说中的误解:

"count(1) 比 count(*) 快" ?

"count(主键) 最快" ?

现实真相:

MySQL 5.7 及以后版本:

count(*) 和 count(1) 性能完全相同

MySQL 优化器会把它们当作一回事

查看执行计划证明:

EXPLAIN SELECT count(*) FROM user_test;

EXPLAIN SELECT count(1) FROM user_test;

EXPLAIN SELECT count(id) FROM user_test;

-- 你会看到:前两个的执行计划完全一样!

性能排序(一般情况):

count(*) ≈ count(1) ?

count(主键列)

count(非主键有索引列) ?

count(非主键无索引列)

为什么 count(列名) 可能更慢?

-- 假设 email 列有索引

SELECT count(email) FROM user_test;

/*

MySQL 需要:

1. 读取索引(如果该列有索引)

2. 检查每个值是否为 NULL

3. 只计数非 NULL 的

如果 email 列没有索引:

1. 读取整行数据(比 count(*) 读的更多)

2. 检查 email 是否为 NULL

3. 只计数非 NULL 的

*/

3. 特殊情况分析

-- 情况1:所有列都不允许NULL

CREATE TABLE user_not_null (

id INT PRIMARY KEY NOT NULL,

name VARCHAR(50) NOT NULL

);

-- 这时候:count(*) = count(id) = count(name)

-- 情况2:空表 vs NULL值

CREATE TABLE empty_table (id INT);

SELECT count(*) FROM empty_table; -- 结果:0

SELECT count(id) FROM empty_table; -- 结果:0

INSERT INTO empty_table VALUES (NULL);

SELECT count(*) FROM empty_table; -- 结果:1

SELECT count(id) FROM empty_table; -- 结果:0 ?

四、实际工作中的选择指南

场景1:统计总行数

-- ? 正确做法

SELECT count(*) FROM orders;

-- ? 错误做法

SELECT count(order_id) FROM orders; -- 万一有NULL呢?

SELECT count(1) FROM orders; -- 能用,但不是标准

场景2:统计有效数据数量

-- 统计有多少用户填写了邮箱

SELECT count(email) FROM users; -- ? 这个场景就该用 count(列名)

-- 统计已完成订单数量(假设 status=2 是已完成)

SELECT count(*) FROM orders WHERE status = 2; -- ?

场景3:统计非重复值

-- 统计有多少个不同的城市

SELECT count(DISTINCT city) FROM users; -- ? count + DISTINCT

-- 统计有多少个城市,排除 NULL

SELECT count(DISTINCT city) FROM users; -- DISTINCT 会自动排除 NULL

五、性能优化技巧

1. 大表优化方案

-- 方案1:使用近似值(适用于统计概览)

SELECT TABLE_ROWS

FROM information_schema.TABLES

WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'big_table';

-- 方案2:分页总数缓存(适用于列表页)

-- 第一次查询时缓存总数,后面定时更新

-- 方案3:使用汇总表

CREATE TABLE stats_daily (

date DATE PRIMARY KEY,

user_count INT,

order_count INT

);

2. 索引优化

-- 为 count(列名) 创建索引

CREATE INDEX idx_email ON users(email);

-- 但注意:count(*) 不一定需要索引,InnoDB有优化

六、有趣比喻帮你记忆

汉堡店排队比喻

-- 有10个人在排队买汉堡

count(*) = "队列里有10个人" ?

count(1) = "我给每人发个号码牌,数有10个牌" ?

count(现金) = "只有8个人带了现金" ?

count(会员卡) = "只有5个人有会员卡" ?

教室点名比喻

-- 教室里有50个座位

count(*) = "教室有50个座位" ?

count(1) = "我在每个座位放本书,最后数有50本" ?

count(学生) = "今天来了45个学生上课" ?(空座位不算)

七、总结与最佳实践

最终建议

统计总行数,一律用 count(*)

这是 SQL 标准写法

性能最优(MySQL有专门优化)

语义最明确

统计某列非 NULL 数量,用 count(列名)

这是它的本职工作

不要用它统计总行数

关于 count(1)

性能与 count(*) 一样

但不够"标准",像方言

建议统一用 count(*)

性能关键点

大表避免频繁 count

考虑使用缓存或汇总表

为 count(列名) 的列加索引

一张图看懂

count(*) -> 总数 -> 最快 -> 推荐使用

count(1) -> 总数 -> 一样快 -> 可用但不标准

count(主键) -> 总数 -> 次快 -> 主键非NULL时可用

count(索引列) -> 非NULL数 -> 较慢 -> 有索引时可用

count(普通列) -> 非NULL数 -> 最慢 -> 谨慎使用

记住口诀:"数总数,用星号;数非空,列名好;数字1,虽高效,不是标准别当宝"朴煞蛔喂

http://www.jsqmd.com/news/611016/

相关文章:

  • 【2025最新】基于SpringBoot+Vue的校园社团信息管理管理系统源码+MyBatis+MySQL
  • 2026年知名的可调机柜底座/电力系统机柜/河北服务器机柜/矿机机柜厂家哪家好 - 行业平台推荐
  • 开源工具Free-NTFS-for-Mac:跨平台NTFS设备高效管理指南
  • 零基础玩转OpenClaw:Qwen3.5-9B镜像云端体验指南
  • Linux线程同步
  • AppImageLauncher:5分钟掌握Linux AppImage应用的终极管理方案
  • 5分钟体验OpenClaw:星图平台Qwen3-4B镜像一键部署方案
  • OpenClaw健康检查:千问3.5-35B-A3B-FP8服务状态监控方案
  • 如何突破抖音视频下载限制:douyin-downloader的全方位解决方案
  • JDBC快速入门
  • c语言错题
  • 【苍穹外卖】Mac前端开发环境搭建:从零到部署的完整指南
  • 【技术解析】MASt3R-SLAM:如何通过两视图先验实现实时稠密三维重建?
  • 沃虎REACH RoHS合规产品如何助力企业应对全球环保法规升级
  • SDXL 1.0电影级绘图工坊实战案例:品牌LOGO多风格延展设计应用
  • 告别旧版配置:基于frp 0.52.3新特性的内网穿透实战搭建
  • 8大AI核心概念,让你秒懂智能体、多智能体系统、RAG、工作流、微调、函数调用、MCP和A2A!
  • C# 13主构造函数+Records+With表达式三重组合技(.NET 8.0正式版实测):DTO层代码减少83%,但需绕过这个编译器Bug
  • QT集成QRencode与Code128:从源码集成到界面绘制的条码生成实战
  • 从 Apache SeaTunnel 走向 ASF Member:一位开发者的长期主义样本悔
  • springboot基于java搭建网站框架音乐系统_714i0lac
  • 芯视野 | Synwit_UI_Creator(ugui)PC端设计器:从零到一构建高效嵌入式UI
  • 别再混淆了!RuoYi-Vue中‘第三方登录’与‘标准单点登录(SSO)’的实现差异与选型建议
  • CompressO:重新定义音视频压缩的开源解决方案
  • AI:词向量模型详解(Word Embedding)
  • GIL终结者来了!Python原生无锁并发的3大工业级模式:MPMC队列、无等待哈希表、RCU读写分离实战(含perf火焰图验证)
  • IMX6ULL 裸机开发:RGB LCD 显示与 PWM 背光控制
  • OpenClaw日志分析:Qwen3-4B-Thinking-2507-GPT-5-Codex-Distill-GGUF快速定位服务异常根因
  • 云原生环境中的边缘AI推理服务
  • 利用Dockerfile打造高效Android持续集成环境