【问题标题】:MySQL ORDER BY Optimization on Multiple JoinsMySQL ORDER BY 对多个连接的优化
【发布时间】:2012-01-30 04:24:12
【问题描述】:

我需要一些帮助来优化我的数据库的一些查询。我确实了解使用索引来帮助连接和 order by 语句以帮助加快速度,但我想知道是否有一些技术可以避免使用文件排序和使用 EXPLAIN 命令时使用临时性。这是我正在使用的示例。

SELECT a.id, DATE_FORMAT(a.submitted_at, '%d-%b-%Y') as submitted_at, a.user_id,
            data1.*, 
            data2.name, data2.type,
            u.first_name, u.last_name               
            FROM applications AS a 
            LEFT JOIN users AS u ON u.id = a.user_id
            LEFT JOIN score_table AS data1 ON data1.applications_id = a.id
            LEFT JOIN sections AS data2 ON data2.id = data1.section_id
            WHERE category_id = [value] && submitted_at IS NOT NULL
            ORDER BY data2.type

再一次,索引在我的查询中得到了正确的使用,就像上面的查询一样。如果我取出 ORDER BY 子句,则查询会通过使用正确的索引快速执行。我了解连接的顺序会影响查询的性能。当我在 users 表上使用 ORDER BY 进行测试时,因为它是“const”之后的下一个表,所以它只会在 EXPLAIN 上使用“Using where,Using Filesort”。如果我转到任何其他表,我们就会遇到“使用临时”问题。

我的问题是:优化这样的查询以更快地运行并且在最佳情况下避免在 EXPLAIN 中使用 filesort/temporary 的最佳方法是什么?我对任何可能性持开放态度:) 我或多或少对如何使这样的查询执行得更好的理论感兴趣,而不是这个确切的查询,因为我必须执行越来越多的这些深层 ORDER BY 查询我正在处理的数据库。

--编辑--

这是上面查询的解释.....

id  select_type     table   type    possible_keys               key         key_len     ref                 rows    Extra
1   SIMPLE          a       ref     category_id,submitted_at    category_id     4           const               49      Using where; Using temporary; Using filesort
1   SIMPLE          u       eq_ref  PRIMARY                     PRIMARY     4           a.user_id           1   
1   SIMPLE          data1   ref     app id                      app id      4           a.id                7   
1   SIMPLE          data2   eq_ref  PRIMARY                     PRIMARY     4           data1.section_id    1   

【问题讨论】:

  • join conditions 中的字段和where 子句中的字段和order by 中的字段上是否有indexes
  • @piotrekkr 是的(以上所有),我刚刚编辑了我的帖子以反映这一点。
  • 由于您对 LEFT JOINed 的表进行 ORDER BY,因此您将无法绕过临时表的创建。这是因为 MySQL 不能从同一个表中驱动查询,它是根据它排序的。
  • 提供表格方案和explain 结果会很有帮助

标签: php mysql optimization join sql-order-by


【解决方案1】:

几件事。

  1. 您确定需要使用“LEFT JOIN”吗?查看查询,您似乎可以使用“INNER JOIN”,这将减少潜在行数。

  2. 您没有发布架构,但我假设 users.id、applications.user_id、score_table.applications_id、applications.id、sections.id 和 score_table.section_id 都是整数?如果它们不是整数,我强烈建议您转换它们。如果不是主键,请确保它们已编入索引。

  3. 我不会运行任何 mysql 级别的数据格式化(即 DATE_FORMAT),因为它会在查询期间产生一些开销,而是我会在应用层像这样格式化数据。

  4. ORDER BY 强制 MySQL 创建一个临时表以便正确排序,因此请确保您绝对需要此功能。如果是这样,请确保 section.type 已编入索引。

  5. 我会考虑使用不同的别名命名约定。 data1 和 data2 非常抽象,很难辨别它们实际指的是什么。例如,我建议您使用要别名的表的缩写结构; applications 变为 app(而不是 a), score_table 变为 score(而不是 data1),等等。

【讨论】:

  • 1.是的,我正在考虑继续使用 LEFT JOIN。它确实正确地提取了数据,并且正是我所需要的。 2. 是的,它们都是整数。 3. 这是我绝对要记住的事情。谢谢你的提示。 4. 是的,我绝对需要该功能,因为数据必须按特定字段排序,并且该字段通常有几级深。 5. 我只是以这种方式命名表,例如。谢谢!
  • @ImmortalFirefly:您可能需要考虑删除 where 子句中的mitted_at,然后运行解释,我认为这就是导致您的查询求助于文件排序的原因。如果是这样,请尝试为 category_id 和 submit_at 添加一个复合索引。
  • 我尝试将查询更改为 ORDER BY a.id(主键),即使删除了 submit_at 上的 DATE_FORMAT(),我仍然得到文件排序
  • @ImmortalFirefly: 不,我的意思是从 WHERE 子句中删除 '&&mitted_at IS NOT NULL',我相信这是导致查询考虑 submit_at 字段的原因,这可能导致使用 temp 和使用文件排序标志。我们可以把它加回来,只是想找出罪魁祸首。
  • @ImmortalFirefly:问题最终是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多