唠唠 MySQL 慢查询:有索引咋还慢?

126 阅读5分钟

咱先聊聊啥叫慢查询哈。慢查询,说白了就是 MySQL 里那些执行起来特费时间的查询语句。打个比方,你去饭店点菜,等了老半天菜都没上,这就相当于查询语句半天没执行完,让人着急。在 MySQL 里,咱们可以自己定个时间门槛,像设定超过 1 秒还没跑完的查询就算慢查询,当然这个时间能按实际情况改。

那为啥会出现慢查询呢?原因挺多的。

首先,要是没给查询的列弄个合适的索引,这就好比在一个超级大仓库里找东西,仓库没分区也没标签,你只能一个角落一个角落慢慢翻,那得多花时间啊,数据库也一样,全表扫描数据,速度自然就慢下来了。

其次,数据量太大也麻烦。就拿一个存用户订单的表来说,要是存了好几千万条订单记录,就算有索引,一些复杂点的查询,要从这么多数据里挑出你要的,也得费不少劲,时间也就花得多了。

还有,查询语句要是写得太复杂,也容易出问题。比如说,你一个查询里又有好几个表连接(JOIN),又套了好几层子查询,还加了一堆复杂函数,数据库处理起来就得绕好几个弯,运算量一大,速度肯定快不了。

最后,服务器性能要是跟不上,也会导致慢查询。这就像你用一台配置特别低的电脑,同时开好几个大型软件,电脑肯定卡得不行。数据库服务器也一样,CPU 性能差、内存不够用或者磁盘读写速度慢,查询执行起来就会拖拖拉拉。

有索引了还会有慢查询吗

很多人觉得,只要给查询语句里的列加了索引,就万事大吉,不会有慢查询了,其实不是这样的。就算查询命中了索引,还是可能出现慢查询的情况。

比如说,索引的选择性不好。啥意思呢?假如有个 “职业” 列,里面就那么几种常见职业,像 “教师”“医生”“工人”,大家选的职业就集中在这几个,就算给这列加了索引,因为重复值太多,数据库通过索引找数据的时候,还是得扫描一大片,起不到很好的筛选作用,查询速度还是提不上去。

再讲讲数据分布不均匀的情况。拿按照创建时间建索引来说,要是大部分数据都集中在最近一两个月,而你要查的是好几年前的少量数据,这时候索引可能就没那么好用了,查询性能就会受影响。

还有个容易忽略的,就是索引维护成本。数据库里数据要是经常增删改,索引也得跟着更新维护。打个比方,你家书架上的书经常被拿走、放新的进来,那你就得时不时整理书架,让书摆放有序。数据库索引也是,维护索引的时候,要是正好有查询请求过来,就会互相影响,导致查询变慢。

咋评估一个 SQL 是不是慢查询

评估一个 SQL 语句是不是慢查询,有好几个办法。

最直接的,就是看它的执行时间。MySQL 有个慢查询日志,专门记录那些执行时间长的查询,或者用一些性能监控工具,也能看到每个查询跑了多久。要是执行时间超过了你设定的那个慢查询时间门槛,那它就是慢查询。

还有个挺好用的办法,就是用 EXPLAIN 语句。这就像是给查询语句做个 “透视”,能看到 MySQL 执行这个查询的具体步骤。它会告诉你有没有用上索引,扫描了多少行数据之类的信息。通过分析这些,你就能知道查询效率咋样。要是发现扫描的行数特别多,或者该用的索引没用上,那这个查询很可能有问题。

另外,还得从业务需求角度考虑。有些查询在业务上对时间要求特别高,比如说一个电商网站实时显示商品库存的查询,要求几百毫秒就得返回结果,要是实际执行要好几秒,哪怕没超过系统设定的慢查询时间,对这个业务场景来说,它也是慢查询,因为满足不了业务需要。

特定场景分析

咱再唠唠 “select * from a where create_time(1 天的范围)” 这个场景。有索引的话,一般来说查起来是挺快的,但也不是绝对的,也可能出现慢查询。

要是表的数据量不大,一天范围内的数据没几条,那这个查询肯定快,因为通过索引能 “嗖” 地一下就定位到要的数据,基本不会有慢查询的问题。

可要是数据量特别大,比如说这个表每天都有海量的数据插入,一天的范围可能涉及到几万甚至几十万条记录,虽然有索引,要是服务器性能一般,或者查询的时候,数据库正好在忙别的耗时操作,像在维护索引、做数据备份之类的,那查询就可能慢下来。还有,要是索引本身有碎片,或者数据分布不均匀,也会影响查询性能,让这个本来看着挺简单的查询,一不小心就变成慢查询了。