MySQL 中 IN 和 EXISTS 的性能选择
外层表小内层表大时 IN 更优。外层表大内层表小时 EXISTS 更优。MySQL 优化器可能会重写两者实际执行计划可能相同。
MySQL 中 ANALYZE TABLE 更新统计信息
ANALYZE TABLE 更新表的统计信息让优化器生成更准确的执行计划。大量数据变更后手动 ANALYZE 可以改善查询性能。InnoDB 自动 analyze 的频率较低。
MySQL 中死锁的定位和排查
SHOW ENGINE INNODB STATUS 输出的 LATEST DETECTED DEADLOCK 部分包含死锁信息和涉及的事务 SQL。分析两个事务的锁请求顺序可以避免死锁。
MySQL 中 AUTO_INCREMENT 的步长和起始值
auto_increment_increment 设置步长auto_increment_offset 设置起始值。主主复制中设置不同步长避免自增 ID 冲突。
MySQL 中 INSERT IGNORE 和 INSERT ON DUPLICATE
INSERT IGNORE 冲突时忽略不插入不报错。INSERT ON DUPLICATE KEY UPDATE 冲突时更新。INSERT IGNORE 不会产生错误日志适合批量导入。
MySQL 中的虚拟列 Generated Column
MySQL 的虚拟列从其他列自动计算得出。VIRTUAL 不存储STORED 存储到磁盘。生成列上可以建索引为 JSON 字段创建函数索引。
MySQL 中行锁和表锁的区别
InnoDB 的行锁只锁定需要修改的行高并发下性能好。MyISAM 的表锁锁定整个表写入会阻塞其他读写。InnoDB 的行锁基于索引如果 WHERE 没走索引会升级为表锁。
MySQL 中的外键约束使用场景
外键约束保证引用完整性删除时 CASCADE 或 SET NULL。但在高并发场景下外键会增加锁开销。很多互联网公司选择在应用层保证引用关系。
MySQL WHERE 条件的执行顺序不影响结果
WHERE 条件的执行顺序不保证从左到右优化器会基于统计信息选择最优顺序。不需要把索引条件放在前面。MySQL 的 WHERE 顺序不影响性能。
MySQL UPDATE JOIN 关联更新
UPDATE t1 JOIN t2 ON condition SET t1.col = t2.col 根据另一张表的值更新当前表。比子查询 UPDATE 更高效。本文展示 UPDATE JOIN 的语法。
MySQL 中自增 ID 不连续的原因
MySQL 自增 ID 不连续的原因包括事务回滚和 insert ignore 跳过重复键。InnoDB 不保证自增值连续只保证递增。本文列出各种跳号场景。
MySQL 中分区表的使用场景
分区表把一张大表按逻辑拆成多个物理分区查询时只扫描匹配分区的数据。适合按时间范围清理历史数据的场景。本文展示 RANGE 分区的定义和查询优化。
MySQL 中 REPLACE INTO 和 INSERT ON DUPLICATE KEY UPDATE
REPLACE INTO 冲突时先删除再插入改变自增 ID。INSERT ON DUPLICATE KEY UPDATE 冲突时直接更新不删除。本文对比两种 upsert 方式的行为差异。
MySQL 大表 DDL 操作导致锁表
MySQL 的大表 ALTER TABLE 会锁住整个表阻塞读写。用 pt-online-schema-change 或 MySQL 8.0 的在线 DDL 可以避免锁表。本文介绍在线变更工具的使用。
MySQL 5.7 升 8.0 后默认字符集变了
MySQL 8.0 将默认字符集从 latin1 改成 utf8mb4升级后已有表的字符集不变但新创建的表和库使用新默认值。本文列出升级后需要检查的地方。
MySQL 字符集 utf8mb4 和 utf8 的区别
MySQL 的 utf8 只支持最多 3 字节的字符存不了 emoji。utf8mb4 支持完整的 Unicode 包括 4 字节字符。新项目应该用 utf8mb4 作为默认字符集。
MySQL IN 子查询性能差改 JOIN
WHERE id IN (SELECT id FROM other) 在 MySQL 中可能比等效的 JOIN 慢因为子查询物化了中间结果。改成 JOIN 形式让优化器更好地选择执行计划。
MySQL 隐式类型转换导致索引失效
WHERE string_col = 123 字符串列和数字比较时 MySQL 把字符串转成数字导致索引失效。改成 '123' 字符串形式可以走索引。本文用 EXPLAIN 展示转换前后的差异。
MySQL 时间列上 ORDER BY 不走索引的可能原因
WHERE DATE(create_time) = today 在时间列上用了函数索引失效导致 ORDER BY 也不走索引。改写为 create_time >= today AND create_time < tomorrow 可以走索引。
MySQL GROUP BY 和 HAVING 的过滤区别
WHERE 在分组前过滤行HAVING 在分组后过滤聚合结果。WHERE 可以用索引HAVING 不能。本文用商品统计的例子说明两者的使用场景。
MySQL 日期函数 NOW 和 SYSDATE 的区别
NOW() 在同一个 SQL 语句中返回相同时间SYSDATE() 每次调用都返回实时时间。在基于语句的复制中 NOW 是安全而 SYSDATE 可能导致主从不一致。
MySQL 删除数据后表文件大小不变
DELETE FROM 只标记行删除文件不会缩小。InnoDB 的 page 合并后空间可复用但不是释放给操作系统。要回收空间用 OPTIMIZE TABLE 或 ALTER TABLE ENGINE=InnoDB。
MySQL 用 UNION 和 UNION ALL 的区别
UNION 自动去重UNION ALL 保留所有行。UNION 需要额外排序去重数据量大时性能比 UNION ALL 差很多。不需要去重的查询应该用 UNION ALL。
MySQL 使用索引排序 ORDER BY 不走 filesort
ORDER BY 和 WHERE 共用同一个索引或者 ORDER BY 字段有独立索引时无需额外排序。Extra 里没有 Using filesort 说明走索引排序。本文解释索引排序的条件。
MySQL 唯一约束和 NULL 的关系
MySQL 的唯一约束允许多行 NULL 值因为 NULL 不等于任何值包括另一个 NULL。业务上需要唯一但不强制填写时这可能不是你想要的行为。本文给出替代方案。
MySQL 清空表数据用 TRUNCATE 还是 DELETE
TRUNCATE 清空表且重置自增 ID 到初始值速度极快但不可回滚。DELETE FROM table 逐行删除保持自增 ID 计数可回滚但速度慢。本文对比两种方式的差异。
MySQL 字符串字段没有索引导致全表扫描
WHERE name = something 在 VARCHAR 字段上如果不建索引即使条件准确也只能全表扫描。前缀索引可以显著减少索引大小但需要选择合适的长度。本文介绍如何确定前缀索引的长度。
MySQL COUNT 哪个最快
MySQL COUNT 哪个最快是开发中经常遇到的问题。本文从实际场景出发分析原因并给出可操作的解决方案适合正在排查这个问题的开发者参考。