【问题标题】:is it always bad to have Using temporary and filesort?使用临时文件和文件排序总是不好的吗?
【发布时间】:2021-07-18 13:48:12
【问题描述】:

我有一种情况,我在 where 子句中指定了最多 100 个主键。

一个示例查询:

select  product_id, max(date_created) AS last_order_date
    from  orders
    where  product_id=28906
      or  product_id=28903
      or  product_id=28897
      or  product_id=28848
      or  product_id=28841
      or  product_id=28839
      or  product_id=28838
      or  product_id=28837
      or  product_id=28833
      or  product_id=28832
      or  product_id=28831
      or  product_id=28821
      or  product_id=28819
      or  product_id=28816
      or  product_id=28814
      or  product_id=28813
      or  product_id=28802
      or  product_id=28800
      or  product_id=28775
      or  product_id=28773
    group by  product_id
    order by  date_created desc

解释显示Using index condition; Using temporary; Using filesort

我知道我应该避免使用Using temporary; Using filesort 进行查询,但是即使对于大型数据集,查询执行时间也很快,我是否必须避免它?我已经给出了一个 ID 列表,所以我能做的就是最好的查询。

如果我决定继续使用该查询,我应该预料到哪些副作用或缺点?

解释输出:

1   SIMPLE  wc_order_product_lookup range   product_id  product_id  8   NULL    3   Using index condition; Using temporary; Using filesort

【问题讨论】:

  • 您使用的是什么版本的 MySQL?较新的版本现在包括运算符 Index Skip Scan(从 Oracle 导入),对于此类情况可以非常快。 product_iddate_created 列是否参与索引?
  • @TheImpaler 我正在 MySQL 5.6 和 MariaDB 10.3.3 上测试它。我对这两个字段都有索引。用 EXPLAIN 更新了帖子。
  • 啊...这些都没有 new 运算符。我认为它是 MySQL 8 的最新版本之一。

标签: mysql sql optimization


【解决方案1】:

照 Gordon 说的做,但要使用

ORDER BY last_order_date DESC

order by date_created desc 没有意义。

如果列表“太长”,它可能切换到表扫描。这可能是 MySQL 和 MariaDB 之间EXPLAIN 的差异。 (结果集将是相同的。)

如果你做EXPLAIN FORMAT=JSON SELECT ...,你可能会发现有两个文件排序。

回到你原来的问题...

“文件排序”和“使用临时”在某些情况下是必要的——尤其是像你的情况。在GROUPs 结果之后,ORDER BY 要求以GROUP BY 未指定的方式进行排序。这需要存储数据并对其进行排序。

“文件排序”是用词不当。在大多数情况下,行位于 RAM 中并且可以非常快速地排序。对于非常大的结果集和其他复杂情况,实际上会使用“临时”“文件”。

优化器将您的ORs 列表转换为IN,就像 Gordon 的回答一样。所以,这两种写法基本上没有区别。 (我觉得IN 更简洁更简洁。)

Using index condition 表示 InnoDB 正在承担通用“处理程序”通常所做的一些工作。 (这很好,但没什么大不了的。)但是,将INDEX(product_id) 替换为INDEX(product_id, date_created) 可能会更好,因为它是“覆盖”,这将由Using index 表示。

“我有两个字段的索引”——这与我推荐的复合索引相同。

您说“100 个主键”,但我怀疑您的意思是“辅助”键。请提供SHOW CREATE TABLE orders 进行讨论。

我不同意老太太的说法:“应该避免使用 Using temporary; Using filesort 进行查询”。这些只是你正在做一些需要如此复杂的事情的线索。很少能“避免”。

【讨论】:

  • 非常感谢您的详细解释。你是对的。这是副钥匙。不幸的是,在这种情况下,我没有选择创建新索引。我无法控制它。
  • @Moon - “没有选择”?即使第 3 方产品试图控制 MySQL,我希望您仍然能够访问并执行 ALTER TABLE ... ADD INDEX ...
【解决方案2】:

文件排序正用于group byorder by。这很难避免。不过,您可能会发现 in 有助于使用 where 子句:

select product_id,  max(date_created)  AS last_order_date
from orders
where product_id in (28906, 28903, 28897, . . . )
group by product_id
order by date_created desc;

【讨论】:

  • 谢谢戈登。如果我继续使用它会有什么副作用或缺点?对于我的用例,执行时间非常快。我只是想看看是否还有其他未知的减速。
  • @Moon 。 .. 听起来您的查询已经在使用产品 ID 上的索引。如果每个产品没有太多行,查询应该有相当不错的性能,
  • 谢谢@Gordon Linoff。鉴于这是在数据集有限的 REST API 中使用的,我认为这会很好。
猜你喜欢
  • 2016-09-04
  • 2012-04-17
  • 2016-09-27
  • 1970-01-01
  • 2011-06-23
  • 2018-08-30
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
相关资源
最近更新 更多