使用“ORDER BY”的简单 SQL 查询需要多 10-20 倍

Posted

技术标签:

【中文标题】使用“ORDER BY”的简单 SQL 查询需要多 10-20 倍【英文标题】:Simple SQL Query takes 10-20 times more with "ORDER BY" 【发布时间】:2019-06-22 23:10:30 【问题描述】:

使用“ORDER BY”的简单 SQL 查询需要 10 到 20 倍的时间。如何加快速度?

我的第一个问题是:

SELECT * 
FROM wp_usermeta 
WHERE meta_key = 'partner' 
AND meta_value = 1 
ORDER BY user_id DESC
LIMIT 5

需要 0.2601 秒。经过一些研究,我可以将其优化为:

SELECT user_id 
FROM wp_usermeta 
WHERE meta_key = 'partner' 
AND meta_value = '1' 
ORDER BY umeta_id DESC
LIMIT 5

这个查询只需要 0.1491 秒,但仍然太多。如果我删除 ORDER BY,只需要 0.0075 秒。

我在 *** 和其他论坛上阅读了很多内容,但我无法获得更好的输出。有人有想法吗?

这是一个标准的 WordPress 用户元表。

【问题讨论】:

与所有相关表的 SHOW CREATE TABLE 语句一样,关于查询性能的问题总是需要对给定查询的 EXPLAIN 是的,您应该始终在查询优化问题中包含表定义,但wp_usermeta 在 WordPress 数据库中是一个非常容易识别的表。 @billkarwin 这不是重点 【参考方案1】:

WordPress 中的 wp_usermeta 表是众所周知的,它在 meta_key 上有一个单列索引。

但这会选择 all 具有指定键的行,这并没有缩小搜索范围。它也无助于排序,所以查询必须做额外的工作来进行排序:

mysql> explain SELECT *  FROM wp_usermeta WHERE meta_key = 'partner'  AND meta_value = 1  ORDER BY user_id DESC LIMIT 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: wp_usermeta
         type: ref
possible_keys: meta_key
          key: meta_key
      key_len: 767
          ref: const
         rows: 1
        Extra: Using where; Using filesort

添加新索引应该会有所帮助:

mysql> alter table wp_usermeta add key (meta_key(191), meta_value(191), user_id);

mysql> explain SELECT *  FROM wp_usermeta WHERE meta_key = 'partner'  AND meta_value = 1  ORDER BY user_id DESC LIMIT 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: wp_usermeta
         type: ref
possible_keys: meta_key_2,meta_key
          key: meta_key_2
      key_len: 767
          ref: const
         rows: 1
        Extra: Using where; Using filesort

即使这表明它正在使用新索引 (meta_key_2),它也无济于事。 key_lenref 表示它只使用索引的第一列。为什么不能同时使用两列?

因为您的查询将整数值 1 与字符串列 meta_value 进行比较。您必须将相似类型,即字符串'1' 与字符串列进行比较:

mysql> explain SELECT *  FROM wp_usermeta WHERE meta_key = 'partner'  AND meta_value = '1'  ORDER BY user_id DESC LIMIT 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: wp_usermeta
         type: ref
possible_keys: meta_key_2,meta_key
          key: meta_key_2
      key_len: 1534
          ref: const,const
         rows: 1
        Extra: Using where

现在它可以使用索引中的第二列来搜索值'1',您可以知道,因为key_len: 1534ref: const,const 表明它使用索引的两列而不是一列。

然后优化器意识到它已经按照user_id的顺序读取数据,所以不需要排序。 “使用文件排序”消失了。

【讨论】:

在大多数情况下,前缀索引不起作用。不查看第一个前缀之后的内容。【参考方案2】:

WP 的“元”表的架构效率低下。但它们可以修复。在 [here] 中,我讨论了一些需要修复的问题。我解释了 191 个杂物,以及 5 个避免它的选项。

而且我没有进入“索引合并相交”,因为复合索引总是(?)更好。

【讨论】:

以上是关于使用“ORDER BY”的简单 SQL 查询需要多 10-20 倍的主要内容,如果未能解决你的问题,请参考以下文章

带有 order by 子句的 SQL 查询

sql ORDER BY 多个字段,排序变慢几十倍,求解?

mysql order by无效问题

Mysql多字段order by用法

mysql 多表 查询 之后 group by 分组 order by 无法按照日期排序

sql里 where和order by一起使用是怎样的顺序