当前位置: 首页 > 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/631310/

相关文章:

  • 告别Oracle:深度解析数据库迁移的真实成本、技术路径与落地实战
  • 【LLM在线学习黄金标准】:基于127个生产案例提炼的4类数据漂移响应阈值+2种安全回滚触发机制
  • 比迪丽FLUX.1效果展示:光影质感与皮肤纹理表现力深度评测
  • 深度学习实战:用多尺度训练提升图像识别准确率(附TensorFlow代码)
  • Windows开发者必看:用Git Bash和Oh My Zsh打造高效终端环境(附避坑指南)
  • 14.封装 LangGraph workflow、补节点级日志与异常兜底
  • 从实验室到金融核心系统:SITS2026代码助手通过等保三级+信创适配双认证的11项硬核改造清单
  • 避开Matlab波导仿真的那些坑:手把手教你用quiver3函数画对三维电磁场箭头图
  • 五一出行必备:Bypass分流抢票神器全攻略
  • ChatGPT App 兼容性争议:为何仅支持23款iPhone机型?
  • 别再只调API了!深入OpenCV手势识别:肤色检测算法全解析与实战对比(RGB/YCrCb/OTSU)
  • 从建模到优化:CST Studio Suite中波导弯头高效仿真全流程解析
  • Lychee-Rerank与LaTeX文档处理:学术论文智能检索系统
  • Transformer架构能效天花板已破?斯坦福+清华最新联合实验:混合精度流水线使Wh/token下降63.4%
  • 国产操作系统实战:在VMware 17.6上完美运行银河麒麟V10 SP3的5个关键步骤
  • 构建企业级模型仓库的完整路径(从零到亿级参数模型纳管的12个关键决策点)
  • WPF新手村教程(七)—— 终章(MVVM架构初见杀)净
  • Pixel Language Portal 高性能计算入门:利用C++与OpenMP实现矩阵乘法并行优化
  • 金融可视化组件实战指南:美国线图、均线图与K线图的应用解析
  • ESP32蓝牙实战:从零构建一个温湿度监测与远程灯控系统
  • ubuntu完全免费人流统计方案
  • LSF cgroups与Cadence daemon starter的兼容性实战:从告警到精准配置
  • 大一C语言课设别慌!手把手教你用结构体和文件操作搞定图书馆管理系统(附完整源码)
  • Phi-4-mini-reasoning效果展示:概率推理题(贝叶斯更新、条件期望)准确输出
  • C#怎么实现批量邮件发送 C#如何用MailKit批量发送个性化邮件和HTML格式邮件【网络】
  • 孤能子视角:AI“创新-幻觉“工程化框架
  • 基于i.MX6UL与IP175D的5端口交换机VLAN配置与驱动开发实战
  • Windows优化神器:3步告别卡顿,让你的电脑飞起来
  • 从数据偏差到部署歧视,全链路公平性评估闭环构建,深度解读ISO/IEC 23053:2023新标实施要点
  • Flux MCP 集成指南