MySQL是当下应用最广泛的开源关系型数据库之一,在各类业务系统中承担着核心数据存储的职责,使用过程中有很多细节会直接影响系统的稳定性和性能,以下整理了23个需要重点注意的要点。

基础语法与数据类型相关注意点
1. 字段类型选择要匹配实际场景
不要盲目使用VARCHAR存储所有文本数据,比如固定长度的手机号、身份证号可以使用CHAR类型,数值类型优先选择符合范围的最小类型,比如存储年龄用TINYINT就足够,避免浪费存储空间。
2. 避免使用NULL作为字段默认值
NULL值会增加索引维护的复杂度,也会让查询条件判断变得更繁琐,如果字段没有特殊要求,尽量设置非NULL的默认值,比如数值类型默认0,字符串类型默认空字符串。
3. 字符集统一设置
数据库、表、字段的字符集要保持一致,建议统一使用utf8mb4,避免乱码问题,同时要注意utf8mb4才是真正的UTF-8编码,支持emoji和特殊字符,不要误用MySQL早期的utf8编码。
4. 自增主键的注意点
自增主键不要手动插入值,否则可能导致后续自增值冲突,同时自增主键在大量删除数据后不会自动收缩,如果需要重置自增值可以使用ALTER TABLE 表名 AUTO_INCREMENT = 新值语句。
5. 时间类型选择
存储时间优先使用DATETIME或者TIMESTAMP,TIMESTAMP占用空间更小但有时间范围限制,DATETIME范围更广,不要使用字符串存储时间,否则无法使用时间相关的函数进行查询和计算。
SQL编写相关注意点
6. 查询时避免使用SELECT *
SELECT *会查询所有字段,增加网络传输开销,也会让索引覆盖失效,应该只查询需要的字段,比如只需要用户id和姓名就写SELECT id,name FROM user。
7. WHERE条件中避免对字段做函数处理
如果在WHERE条件中对字段使用函数,会导致索引失效,比如要查询2024年创建的用户,不要写WHERE YEAR(create_time) = 2024,可以改成WHERE create_time >= '2024-01-01 00:00:00' AND create_time < '2025-01-01 00:00:00'。
8. 模糊查询的通配符位置
LIKE查询时,通配符放在开头会导致索引失效,比如LIKE '%张三'无法使用索引,而LIKE '张三%'可以使用前缀索引,如果必须做全模糊查询,可以考虑使用全文索引。
9. 合理使用LIMIT分页
大偏移量的分页查询性能很差,比如LIMIT 100000,10会先扫描前100000条数据再取10条,优化方式可以是先通过索引拿到主键,再关联查询,示例如下:
-- 优化前的大分页查询 SELECT * FROM user ORDER BY id LIMIT 100000,10; -- 优化后的分页查询 SELECT * FROM user u JOIN (SELECT id FROM user ORDER BY id LIMIT 100000,10) tmp ON u.id = tmp.id;
10. 避免隐式类型转换
如果字段是字符串类型,查询时条件值要加引号,否则会触发隐式类型转换,导致索引失效,比如手机号字段是VARCHAR类型,不要写WHERE phone = 13800138000,要写成WHERE phone = '13800138000'。
11. 批量操作代替循环单条操作
插入或者更新数据时,尽量使用批量操作,比如批量插入可以写成INSERT INTO user(name,age) VALUES('张三',18),('李四',20),比循环执行单条插入效率高很多。
12. 注意GROUP BY的排序特性
MySQL中GROUP BY默认会对分组字段进行排序,如果不需要排序可以加上ORDER BY NULL来避免额外的排序开销,提升查询效率。
索引设计相关注意点
13. 不要盲目创建索引
索引不是越多越好,每个索引都会占用存储空间,也会降低插入、更新、删除的性能,一般单表的索引数量建议控制在5个以内,优先给查询频繁、区分度高的字段创建索引。
14. 联合索引遵循最左前缀原则
联合索引(a,b,c)只能生效于a、a+b、a+b+c的查询条件,无法生效于b、c、b+c的查询条件,设计联合索引时要将区分度最高的字段放在最左边。
15. 避免索引失效的场景
除了前面提到的函数处理、通配符开头、隐式类型转换之外,使用OR连接条件时如果其中一个字段没有索引,整个查询也不会使用索引,使用NOT IN、!=、<>操作符时也容易导致索引失效。
16. 定期清理冗余索引
冗余索引会浪费存储空间,比如已经有了联合索引(a,b),就不需要再单独创建a的索引,可以通过SHOW INDEX FROM 表名查看表的索引情况,定期清理无用的冗余索引。
17. 长文本字段使用前缀索引
如果需要对较长的字符串字段创建索引,比如文章内容字段,可以创建前缀索引,只索引字段的前N个字符,比如CREATE INDEX idx_content ON article(content(100)),N的长度要根据字段的实际区分度来定。
事务与锁相关注意点
18. 事务尽量短小
事务持有锁的时间越长,阻塞其他操作的概率就越高,所以事务中要尽快提交或者回滚,不要在事务中做耗时的操作,比如调用外部接口、处理大量业务逻辑。
19. 避免死锁
死锁通常是因为多个事务以不同的顺序获取锁导致的,设计业务时要尽量保证所有事务以相同的顺序获取资源,同时可以设置合理的锁等待超时时间,通过innodb_lock_wait_timeout参数调整。
20. 合理使用事务隔离级别
MySQL默认的事务隔离级别是REPEATABLE READ(可重复读),如果业务不需要这么高的隔离级别,可以调整为READ COMMITTED(读已提交),能减少间隙锁的使用,提升并发性能。
运维与性能相关注意点
21. 定期备份数据
数据备份是重中之重,要制定合理的备份策略,比如每天全量备份,每小时增量备份,备份文件要存储到异地,避免服务器故障导致数据完全丢失,同时定期验证备份文件的可恢复性。
22. 关注慢查询日志
开启慢查询日志,定期分析慢查询语句,优化性能瓶颈,慢查询的阈值可以通过long_query_time参数设置,一般建议设置为1秒,根据实际业务调整。
23. 避免大表的全表操作
对于数据量很大的表,不要做全表更新、全表删除操作,全表删除可以使用TRUNCATE TABLE代替DELETE,效率更高,全表更新要分批进行,避免锁表时间过长影响业务。