MySQL查询太慢?5个最常见的原因和解决办法

王尘宇 问题解答 1

上周有个客户的WordPress后台打开文章列表要等8秒,前台首页也要4秒。我登上去一看,MySQL的慢查询日志里躺着三条超过2秒的SQL。改完之后,后台0.3秒,前台0.8秒。这类问题我处理过不下二十次,最常见的原因就五个。

第一个原因:没加索引。这是最最最常见的。一张10万行的表,按某个字段查,没索引的话MySQL得全表扫描。加一条ALTER TABLE xxx ADD INDEX(field_name),查询时间从2秒变成0.01秒。怎么找缺索引的表?看慢查询日志,或者用EXPLAIN命令分析SQL执行计划,type列显示ALL就是全表扫描,该加索引了。

第二个原因:SELECT *。很多程序写SQL的时候习惯SELECT *,把所有字段都取出来。一张表如果有TEXT类型的大字段(比如文章内容),每次都把内容读出来,数据传输量巨大。改成SELECT id, title, date只取需要的字段,速度能快一倍不止。WordPress的wp_posts表就有post_content这种大字段,文章列表页根本不需要它。

第三个原因:JOIN太多。有些程序或者插件写了一个四五张表的JOIN查询,每张表几万行,JOIN起来慢得要命。解决办法:能拆成多次查询就拆。比如先查出文章列表(10条),再用WHERE id IN (...)查分类和标签。两次简单查询比一次复杂JOIN快,而且更容易加索引。

第四个原因:子查询。MySQL 5.7以下对子查询的优化很差,一个IN (SELECT ...)的子查询可能执行几分钟。改成JOIN写法,或者用临时表中转,速度差距是数量级的。MySQL 8.0对子查询优化好了不少,但如果还在用5.7,这个问题很常见。

第五个原因:表太大没分表。单表超过500万行,即使有索引,查询速度也会明显下降。WordPress的wp_postmeta表特别容易膨胀,每个插件都往里塞数据。定期清理无用的meta数据:DELETE FROM wp_postmeta WHERE meta_key LIKE '_transient_%',清理transient缓存记录。如果表已经大到没法靠清理解决,考虑按时间分表或者归档旧数据。

快速排查流程:一,开慢查询日志(set global slow_query_log=1),阈值设1秒;二,等一天,看日志里哪些SQL最慢;三,用EXPLAIN分析慢SQL;四,根据结果加索引、改查询、清理数据。一般情况下,加索引能解决70%的慢查询问题。

宝塔面板的phpMyAdmin里也能看状态,进到「状态」标签页,看「慢查询」和「临时表」两个指标。慢查询数量持续增长,说明有SQL需要优化。临时表创建在磁盘上的比例超过10%,说明tmp_table_size太小或者查询需要优化。

标签: mysql 性能优化 慢查询

发布评论 0条评论)

  • Refresh code

还木有评论哦,快来抢沙发吧~