【问题标题】:MySQL Left Joining on Limited QueriesMySQL 对有限查询的左连接
【发布时间】:2016-08-30 07:20:02
【问题描述】:

我注意到我在一个相当大的表上执行的某个查询在服务器处于高负载下时变得非常慢:

SELECT large.*, users.username 
FROM large
LEFT JOIN users ON large.user_id = users.id
ORDER BY large.abc 
LIMIT 30

large.user_idusers.id 都已编入索引。)

因此,经过进一步检查,我意识到这是由于连接查询造成的,因为删除连接查询使其变得即时。此外,重写查询也一样快。

SELECT t.*, users.username 
FROM (
  SELECT * FROM large ORDER BY large.abc LIMIT 30
) as t 
LEFT JOIN users ON t.user_id = users.id

这是什么原因?第一个查询是否在排序和限制之前连接所有行,并且是解决此问题以使用第二个查询的最佳/唯一方法?

【问题讨论】:

  • 你的第一个查询甚至不应该运行,因为它的语法错误
  • 就像@TinTran 所说,语法是错误的。您在加入之前订购。
  • @TinTran 我的错误,已修复
  • largeusers是什么关系?多对多还是一对多还是多对一还是一对一?
  • 我之所以问,是因为我猜如果 order by 有更多行要处理,它会更慢。在第二个查询中,您在加入之前将其限制为 30 行。跨度>

标签: mysql join


【解决方案1】:

在您的第一个查询中,您将large 中的每一行加入到其对应的用户,对large 中所有现在加入的行进行排序,然后丢弃除 30 之外的所有行。在您的第二个查询中,您订购 large,丢弃除 30 之外的所有,然后将 large 子集加入到 users。因此,关键的区别在于连接了多少行。

我想查看这些查询计划,但我怀疑第二个查询更快,因为临时表是可读的,从磁盘分页操作(它只有 30 行)比第一个查询(它有“大量”行)。

通常子选择较慢,因为它们绕过优化器的连接算法选择并且必须完全依赖解析查询,但在这种情况下,因为我们知道子选择只有 30 行,它似乎比内置的-在连接优化器中。

我怀疑如果您从子选择中删除 LIMIT 30 并将其放在外部查询中,您会看到比第一个查询更差的性能。但是,EXPLAIN 的输出将在很大程度上解决这个谜团。

【讨论】:

    【解决方案2】:

    我可以根据我的 SQL fiddle 提出建议并尝试一下并告诉我

    CREATE INDEX large_abc_index ON large(abc);
    

    第一个查询似乎更简单并且使用了正确的键。 我在这里使用了解释命令来解释查询。 http://sqlfiddle.com/#!9/784faf/1

    【讨论】:

    • 您在问题中没有提到这一点。也许在你的环境中尝试解释命令,看看它在做什么
    • 我能想到的唯一其他想法是,如果您将大表索引为两列索引,如 abc 和 userid 索引在一起。这会使第一次查询变慢。至少 sqlfiddle.com 中的解释是这样的。
    【解决方案3】:

    尝试根据http://www.w3schools.com/sql/sql_join_left.asp这个语法重新排序你的查询

    应在订购前完成连接。

       SELECT large.*, users.username FROM large LEFT JOIN users ON large.user_id = users.id ORDER BY large.abc LIMIT 30
    

    【讨论】:

      猜你喜欢
      • 2017-04-22
      • 1970-01-01
      • 2023-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多