索引非万能,函数、隐式转换、like左通配等致失效;count(*)无where时与count(1)/count(column)性能相同;join慢主因驱动表误判或缺索引;order by rand()复杂度高禁用;索引还拖慢写入。

为什么加了索引查询还是慢
索引不是万能的,WHERE 条件中用了函数、类型隐式转换、或 LIKE 以通配符开头(如 LIKE '%abc'),都会导致索引失效。MySQL 5.7+ 对 JSON 字段的路径表达式也容易忽略索引,除非显式创建函数索引。
实操建议:
- 用
EXPLAIN查看type是否为range或更优,避免ALL(全表扫描) - 检查
key列是否命中预期索引;若为NULL,说明没走索引 - 对
ORDER BY和GROUP BY字段,考虑联合索引覆盖排序需求,避免Using filesort - 字符串字段比较时,确认两边字符集和排序规则一致,否则触发隐式转换
如何写 COUNT 查询才不拖垮线上服务
COUNT(*) 在 InnoDB 中需扫描索引树(通常是主键),数据量大时非常耗时。更糟的是,很多人误用 COUNT(column) 或 COUNT(1),以为有性能差异——其实三者在无 WHERE 时执行计划完全一样。
实操建议:
- 统计总数且允许误差:用
SHOW TABLE STATUS查Rows字段(仅作估算) - 高频精确计数:维护一个单独的计数表,用事务保证增减原子性
- 带条件的
COUNT:确保WHERE字段有索引,且避免在该字段上做计算(如COUNT(IF(status=1, 1, NULL))会强制扫全表) - 分页查总数 + 数据时,别先
COUNT(*)再LIMIT,改用游标分页或延迟关联
JOIN 太慢,是该加索引还是改写 SQL
多表 JOIN 性能差,90% 源于驱动表选择错误或连接字段缺失索引。MySQL 默认用小结果集做驱动表,但优化器有时会误判,尤其当统计信息过期时。
Hishop.5.2.BETA2版主要更新: [修改] 进一步优化了首页打开速度 [修改] 美化了默认模板 [修改] 优化系统架构,程序标签及SQL查询效率,访问系统页面的速度大大提高 [修改] 采用了HTML模板机制,实现了前台模板可视化编辑,降低模板制作与修改的难度. [修改] 全新更换前后台AJAX技术框架,提升了用户操作体验. 店铺管理 [新增] 整合TQ在线客服 [修改] 后台广告位增加
实操建议:
- 被驱动表的
ON字段必须有索引(最好是前导列),否则变成嵌套循环 + 全表扫描 - 用
STRAIGHT_JOIN强制指定驱动表顺序,比依赖优化器更可控(但需配合EXPLAIN验证) - 避免
SELECT *,只取必要字段;大字段(TEXT/BLOB)会显著拖慢临时表和网络传输 - 三张及以上表
JOIN时,优先考虑拆成两个两表JOIN,中间结果用临时表或应用层缓存
ORDER BY RAND() 为什么绝对不能用在生产环境
ORDER BY RAND() 会让 MySQL 为每一行生成随机数、排序、再取前 N 行——时间复杂度是 O(N log N),N 是满足条件的行数。哪怕只有 10 万行,也可能卡住整个连接池。
实操建议:
- 替代方案:先用
SELECT COUNT(*)得到总数N,应用层生成随机 offset(如rand() % N),再用LIMIT offset, 1 - 如果要取多条随机记录,可先查出所有主键 ID 到内存,随机抽样后拼成
WHERE id IN (...)查询 - 对超大表,考虑给表加自增
row_number列并建立索引,用范围随机代替全量排序
最常被忽略的一点:索引本身会拖慢写入,并占用磁盘和内存。上线前务必确认新增索引是否真被查询用到,而不是堆在那里白占资源。









