MySQL 执行一条 select 语句,期间发生了什么?
Laiyong Wang Lv5

参考网址

https://www.xiaolincoding.com/mysql/base/how_select.html

本文记录下基于 SQL 查询流程,可能导致查询速度慢的情况(自己总结,细节部分 chatGPT ,错误欢迎指正)

  1. 网络原因
    连接 mysql 服务使用 tcp ,三次握手避免不了,四次挥手的时间取决于是短链接还是长连接
    由于 MySQL 在执行查询过程中临时使用内存管理连接对象,如果长连接累计很多,将导致 MySQL 服务占用内存太大,可能会导致系统变慢,甚至会被系统强制杀掉,可定期断开长连接或者客户端主动重置连接(使用函数 mysql_reset_connection())

  2. 查询缓存
    字面意思,以sql查询语句为键,sql查询语句的结果为值,若是缓存有则直接返回,无需查表来提升查询速度。
    所以写sql时尽量将长sql拆分成多个短sql,便于命中缓存。
    但是对于更新比较频繁的表,查询缓存的命中率很低,因为只要一个表有更新操作,那么这个表的查询缓存就会被清空。若刚缓存了个查询结果很大的数据且没被使用的时候,刚好这个表有更新操作,查询缓冲就被清空了,相当于缓存了个寂寞
    所以MySQL 8.0 版本直接将查询缓存删掉了,也就是说 MySQL 8.0 开始,执行一条 SQL 查询语句,不会再走到查询缓存这个阶段了。
    所以查询缓存MySQL8.0版本之前可使用,且最好时查询功能较多的系统来进行使用

  3. 索引

    • 未使用索引
      就是未使用索引,导致全表查询
    • 索引失效
      • 隐式转化(常见于使用订单号查询订单,直接一串数字,不会使用索引)
        列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
        据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描
        隐式转换name = ‘111’ 会使用到 name = 111 不会使用到
        因为当name值为111a 111q 111sxzcs都会跟111匹配
      • 不符合索引最左前缀原则
        对于复合索引,只有在查询的条件满足索引的最左前缀时,索引才能被充分利用。如果查询条件不符合最左前缀原则,那么索引可能无法有效使用,导致索引失效。
      • 使用函数或表达式
        查询中使用了函数或表达式对索引列进行了处理,那么索引可能无法被有效利用。例如,WHERE DATE_FORMAT(date_column, ‘%Y-%m’) = ‘2023-12’,这种情况下,即使 date_column 上存在索引,也无法被利用
        还有常用的 like 语句,若是时%开头,也会索引失效
      • 数据分布不均匀(这个我认为是创建表时的问题,重复率太高就不该有索引)
        索引列上的数据分布不均匀,例如某些值出现的频率过高或过低,那么索引可能无法提供良好的性能,甚至导致索引失效
      • 数据量过大
        对于某些大型表,索引可能无法完全载入内存,这样在执行查询时会导致频繁的磁盘 I/O 操作,影响查询性能
      • 使用 NOT、OR 等条件(这个我不熟,贴个图片,免得以后再看忘了)
        upload successful
  4. 比较好玩的问答

    • 同一条sql,同一个数据库,早上查询很快,下午很慢,为什么
    • 数据库服务器负载(可回答),网络问题(可回答),查询缓存(可回答),索引失效(可回答,为什么会失效?这点非常好玩,因为从上午到下午,表里面可能插入了大量数据,导致数据分布不均匀还有数据量过大,参考第三点)
 Comments