主要的存储引擎
InnoDB:支持事务、支持行锁、支持外键。
MyISAM:不支持事务,只支持表锁。
索引结构
下面主要介绍InnoDB存储引擎的B+Tree索引类型
索引分为聚集索引和非聚集索引:
聚集索引:主键索引就属于聚集索引,该树的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据,这样就不用再回表查询一次数据。
非聚集索引:非聚集索引并不像聚集索引那样在叶子节点存储数据,而是存储指向数据的指针,当查询的时候刚好满足覆盖索引的要求的时候则可直接返回数据,如果不是覆盖索引则要再通过指针查询一次。
主键的类型
为了提升查询效率,主键建议是自增类型,因为这样每次插入新的记录,记录就会添加到当前索引节点的后续位置,当一页写满后,就会自动开辟一个新的页,自增的主键会形成一个紧凑的索引结构从而减少页数;并且每次插入也不需要移动已有数据,因此效率很高。
主键要选择较短的数据类型,Innodb引擎普通索引都会保存主键的值,较短的数据类型可以有效的减少索引的磁盘空间,提高索引的缓存效率。
最后是数值类型的,因为插入和查询的时候都会比较主键值的大小,数值类型的比较效率会比其它类型的更高。
主键是不可重复的,即便在高并发场景下,否则会对业务造成巨大的影响。
总结:在满足不可重复的基础上,主键需要是递增的数值类型并且需要尽可能的短,可以考虑使用雪花算法(可以参考美团leaf:tech.meituan.com/2019/03/07/…)。
sql优化技巧
- 使用like的时候避免%开头,否则会造成索引失效,如果有需要,建议使用ES等搜索引擎。
- 禁止使用select * ,查询多余的字段会浪费网络资源。
- 禁止使用JOIN关联过多的表,可以考虑分为多个sql进行查询(需要根据实际的业务场景从数据量和调试的结果来进行分析)。
- 能批量操作的的数据尽量批量操作,例如批量插入和批量删除。
- 数据量大的时候建议使用pt-online-schema-change进行表结构修改,避免对线上业务造成影响。
- 不会重复的数据使用UNION ALL而不是UNION,因为UNION ALL的去重会有一定的性能损耗。
- 不建议使用外键,考虑在应用层解决关联问题。
- 字段可以适当冗余,提高查询性能,但必须考虑数据一致以及是否会频繁修改以及是否为大字段。否则冗余反而会影响性能。
- 选择合适的字符存储长度,可以有效节约数据库表空间以及索引存储,还可提高索引效率。
- 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。
- 当我们在建立组合索引的时候,能区分较多数据的放在最左侧。
- 避免在where后使用or来连接条件,否则可能会引起索引失效。
- 索引无法存储null值,所以where的判断条件如果对字段进行了null值判断,将无法使用索引而导致全表扫描(将索引列进行建树操作,其中会进行很多的比较,null值不确定所以确定不了其在叶子节点的位置)。
- 尽量少使用in操作,如果要用,后面的集合元素数量不宜过大(尽量控制在一千以内)。
- 禁止使用负向查询NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描。
- 注意隐式类型转换会导致索引失效。
- 在索引列上进行函数计算,会导致索引失效。
- 禁止存储大文件或者照片,建议使用专业的文件服务器,数据库只存地址。
- 单表的列数不宜过多(最好小于30)。
- 不要使用ENUM的字段类型,可以考虑TINYINT代替。
- 慎用存储过程,存储过程难以调试和扩展,更没有移植性。
- 每个表的索引数量不宜过多,针对多条件查询可以考虑联合索引,因为每创建一个索引都需要创建一个索引树并且当数据修改的时候需要对每个索引树进行更新,所以索引使用不当反而会造成一些额外的开销。
- 消除对count(列名)和count(*)的误解,count(*)会统计值为null的行,而count(列名)不会统计此列为null的值。
- 通过SELECT IFNULL(SUM(字段名),0)来避免NPE。
- count(distinct col)计算该列除NULL外的不重复行数。
- 小数类型使用decimal。
- 表必须含有主键、创建时间和修改时间的字段。
- 如果可以请使用覆盖索引,这样一次就能把数据查出来,无需回表查询,提高查询效率。