前言
SQL调优在项目中是比较常见的,SQL调优不仅仅包括SQL语句的编写,其中还应包括了数据库的表设计,数据库的配置架构(主从复制,读写分离),索引的使用,当然在数据量如果很大的情况下还应包括分库分表这些,今天我们就来谈谈我在开发学习这方面的经验。
SQL调优是指通过对数据库系统中的SQL查询及设计架构进行分析、优化和改进,以提高查询性能、减少资源消耗、降低响应时间、提高系统稳定性和可靠性的过程。
表设计优化
合理的范式设计:根据业务需求和数据特点,进行合理的范式设计,避免数据冗余和不一致性,提高数据存储效率和可靠性。
适当的反范式设计:对于一些需要频繁查询的字段,可以考虑进行反范式设计,将相关字段冗余存储,以减少数据表连接的次数,提高查询性能。
合理选择字段类型:根据实际存储内容选择合适的字段类型,如整型、字符型、日期型等,以减少存储空间浪费和提高数据处理效率。
要根据字段的内容来选择合适的数据类型。对于数值类型的字段,可以根据实际情况选择合适的类型,例如:
- TINYINT: 用于存储范围较小的整数,通常用于存储布尔值或者状态码等。
- INT: 用于存储普通整数,通常用于存储计数器、ID等。
- BIGINT: 用于存储范围较大的整数,通常用于存储较大的计数器、ID等。
对于字符串类型的字段,也需要根据存储内容来选择合适的类型,例如:
- CHAR: 用于存储定长字符串,适合存储长度固定的字符串,例如国家代码、性别代码等。
- VARCHAR: 用于存储可变长度字符串,适合存储长度不固定的字符串,例如姓名、地址等。
- TEXT: 用于存储较大文本数据,适合存储大段文本、文章内容等。
优化索引设计:为常用的查询条件创建合适的索引,以加快查询速度,同时避免过多的索引导致更新性能下降。
优化主键设计:选择合适的主键,避免使用过长或者频繁变动的字段作为主键,以提高数据插入和更新的性能。
索引优化
索引是帮助MySQL高效获取数据的数据结构,主要是用来提高数据检索的效率,降低数据库的IO成本,同时通过索引列对数据进行排序,降低数据排序的成本,也能降低了CPU的消耗。
通俗来说, 索引就相当于一本书的目录, 可以根据页码快速查找到指定的内容, 目的就是加快数据库的查询速度,但这也就意味着书中如果要增加一个章节,修改目录是比较麻烦的,使用索引适用于经常查询很少修改的业务
在 MySQL 中,通常有以下两种方式访问数据库表的行数据:
1) 顺序访问
- 顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。
- 顺序访问实现比较简单,但是当表中有大量数据的时候,效率非常低下。例如,在几千万条数据中查找少量的数据时,使用顺序访问方式将会遍历所有的数据,花费大量的时间,显然会影响数据库的处理性能。
2) 索引访问
- 索引访问是通过遍历索引来直接访问表中记录行的方式。
- 使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针排序。
- 注意: 建立索引后, 查询速度不一定会变快,例如, 你在teacher表中建立了关于id的索引, 如果你按照name查询, 那么查询速度也不会变快,查询得用到你建立的索引
读写分离,主从复制优化
MySQL读写分离是一种常见的数据库架构设计模式,用于解决高并发场景下数据库的性能和可扩展性问题。它通过将读操作和写操作分离到不同的数据库服务器上,实现了负载均衡和提高数据库性能的效果。
在MySQL读写分离模式中,通常有一个主数据库(Master)用于处理写操作,多个从数据库(Slaves)用于处理读操作。主数据库负责接收并处理所有的写请求,然后将写入的数据同步到从数据库。从数据库则负责处理读请求,提供查询功能。
①当Master节点进行insert、update、delete操作时,会按顺序写入到binlog中。
②salve从库连接master主库,Master有多少个slave就会创建多少个binlog dump线程。
③当Master节点的binlog发生变化时,binlog dump 线程会通知所有的salve节点,并将相应的binlog内容推送给slave节点。
④I/O线程接收到 binlog 内容后,将内容写入到本地的 relay-log。
⑤SQL线程读取I/O线程写入的relay-log,并且根据 relay-log 的内容对从数据库做对应的操作。
sql语句优化
- 尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描
- 尽量避免使用in 和not in,会导致引擎走全表扫描
- 尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描
- 尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描
- 尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描
- 使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。
- 避免使用隐式类型转换,否则造成不使用索引
- 避免使用
SELECT *
:只选择需要的列,避免不必要的数据传输和处理。 - 避免使用通配符(
*
)选择所有列,而是只选择需要的列。使用WHERE
子句限制返回的行数,避免不必要的数据传输和处理。 - 多表关联查询时,小表在前,大表在后
- 如果是聚合查询,尽量用union all代替union ,union会多一次过滤
MySQL通过创建并填充临时表的方式来执行union查询。除非确实要消除重复的行,否则建议使用union all。原因在于如果没有all这个关键词,MySQL会给临时表加上distinct选项,这会导致对整个临时表的数据做唯一性校验,这样做的消耗相当高。