【问题标题】:MySQL sotring by two culmns performanceMySQL 按两列排序的性能
【发布时间】:2023-03-22 16:40:01
【问题描述】:

我有这个问题:

SELECT  *
    FROM  `EpisodeDetailed`
    WHERE  Language LIKE "%en%"
      AND  AddedDate >= "2020-01-13"
      AND  (Tags="1509"
              OR  Tags LIKE "%1509"
              OR  Tags LIKE "1509%"
              OR  Tags LIKE "%1509%"
           )
    ORDER BY  AddedDate, Votes
    LIMIT  50 

而且我用的时候不到0.1s:

ORDER BY AddedDate ASC, Votes ASC

ORDER BY AddedDate DESC, Votes DESC

但是我用的时候很慢(大约4s)

ORDER BY AddedDate ASC, Votes DESC

ORDER BY AddedDate DESC, Votes ASC

为什么?

我的索引:

【问题讨论】:

  • Curious ORDER BY addedDate, Votes 与 ORDER BY addedDate ASC, Votes ASC , ASC 为默认值。
  • 您在 AdditionalDate 和 Votes 列上有索引??
  • EXPLAIN SELECT... 输出什么?

标签: mysql sql indexing


【解决方案1】:

您在AddedDate asc, Votes asc 上有一个索引。

MySQL 可以(显然)以两种方式使用它:

  1. 它可以从头开始扫描到最后。支持order by AddedDate asc, Votes asc
  2. 它可以从末尾开始扫描到开头。支持order by AddedDate desc, Votes desc

它没有做的是跳转到AddedDate 的每个值并向后 扫描该值。唉。它决定需要单独对数据进行排序。

对于其他两种情况,您可以在 AddedDate asc, Votes desc 上添加索引。

【讨论】:

  • 怎么添加?我尝试了“CREATE INDEX test_stack ON EpisodeDetailed (AddedDate asc, Votes desc)”,但它似乎创建了忽略 asc 和 desc 的正常索引
  • @MateuszKaflowski。 . .您可以查看文档:dev.mysql.com/doc/refman/8.0/en/descending-indexes.html。 MySQL 确实支持它们,但这取决于 MySQL 的版本和存储引擎。
【解决方案2】:

也许您可以尝试更改您的查询。例如:

SELECT * FROM `EpisodeDetailed` 
WHERE `Language` RLIKE 'en' 
AND `AddedDate` >= "2020-01-13" 
AND `Tags` RLIKE '1509' 
ORDER BY UNIX_TIMESTAMP(`AddedDate`) ASC, `Votes` DESC LIMIT 50;

此外,如果您安装了MariaDB,请查看here。我想你会觉得它最有趣。

【讨论】:

  • RLIKE 往往比 LIKE 慢。 ORDER BY 中的函数调用消除了任何索引使用。混合方向(ASC/DESC)不能使用索引(直到 MySQL 8.0)。
  • @RickJames 你是对的,RLIKE 往往会慢一些,但如果表被正确索引,则存在细微差别。是的,混合方向只是MySQL 8 的一个功能。
  • RLIKE,据我所知,从不使用索引。 LIKE 'abc%' 可以使用索引;它实际上是一个“范围”。但是,languageTags 都使用前导通配符,从而阻止了任何有用的索引。
  • @RickJames 早在 2003 年就有一个请求 bugs.mysql.com/bug.php?id=747 通过有益地使用索引来加快正则表达式的速度,但你是对的 RLIKE 并没有从中受益索引,但我们谈论的是正则表达式,所以即使扫描更多行,目的也是为了快速。如果数据集太大,则应在查询或表设计上采用更好的方法。
【解决方案3】:

有多种因素阻碍了该查询的加速:

  • 带有前导通配符的 LIKE 不能使用索引
  • 无法优化 WHERE 子句中的多个范围(您有 3 个)。一个可能是索引,但其他不能。
  • 如果没有 ORDER BY,执行过程会简单地遍历表,检查每一行。如果还有 LIMIT,则查询可能或可能不会快速完成,具体取决于匹配的行数以及它们在表中出现的位置。
  • 使用 ORDER BY(并且因为没有索引可以处理所有 WHERE),执行必须在考虑 ORDER BY 或 LIMIT 之前所有匹配的行。
  • 有时使用索引比不使用索引要慢。当需要检查大多数行但优化器无法识别时,就会发生这种情况。它可能会更慢,因为索引需要深入数据才能查看行的其余部分。

也许……

  • language。也许en 总是在左边?如果是这样,LIKE 'en%' 可能会稍微快一些。
  • tagsFULLTEXT 怎么样?如果适用,使用MATCH(tags) AGAINST('+1509' IN BOOLEAN MODE) AND the other clauses 会快很多

【讨论】:

  • MATCH AGAINST 有很大帮助。谢谢。
猜你喜欢
  • 2012-10-19
  • 1970-01-01
  • 2012-02-05
  • 2010-10-05
  • 1970-01-01
  • 2015-12-27
相关资源
最近更新 更多