【问题标题】:Understand how DBMS executes IN query了解 DBMS 如何执行 IN 查询
【发布时间】:2020-03-08 00:42:28
【问题描述】:

我的查询有性能问题,我找到了解决方案,但我真的不明白为什么我有问题,所以有人可以解释一下... 我有 2 个表:流(几百万行)和设备(

我的第一个问题是:

SELECT * FROM Flow WHERE FlowId IN (SELECT MAX(FlowId) FROM Flow GROUP BY DeviceId)

执行时间 > 200 秒。

如果我先执行子查询(我在 0.01 秒内得到结果),然后在查询中使用结果:

SELECT * FROM Flow WHERE FlowId IN (93143922, 93143921)

我的结果不到一秒钟... DBMS 如何执行第一个查询?我认为流程是: 首先执行子查询,然后在“主”查询中使用结果?如果我手动执行此步骤,查询速度很快,所以这绝对不是它的工作方式:(

我的解决办法是这样的:

SELECT * FROM Flow f
INNER JOIN Devices d on d.DevicesId = f.DeviceId
INNER JOIN (SELECT MAX(FlowId) as FlowId FROM FLOW GROUP BY DeviceId) maxFlow
 ON maxFlow.FlowId = f.FlowId

但我需要知道它是如何与 IN 一起工作的 :)

【问题讨论】:

标签: mysql sql performance subquery


【解决方案1】:

IN 有时不能很好地优化。这有几个原因:

  • 需要对子查询的结果进行“重复数据删除”。您可能知道没有重复项,但这对于引擎来说很难知道。
  • 引擎很难推测从IN 返回的行数

我发现相关子查询通常具有最佳性能:

SELECT f.*
FROM Flow f
WHERE f.FlowId = (SELECT MAX(f2.FlowId)
                  FROM Flow f2
                  WHERE f2.DeviceId = f.DeviceId
                 );

特别是,这可以利用Flow(DeviceId, FlowId) 上的索引。

【讨论】:

    【解决方案2】:

    您的情况只会发生在非常糟糕的优化器或任意字段上的 DB 语法不标准的情况下。请注意,在 IN 子句中,您放置了字段 FlowIdDeviceId。默认情况下,大多数优化器可以理解是指IN子句内部的常量表的值,但有些人可能认为它受到外部范围的影响,因此IN内部的细节需要重新评估每行外扫描。

    优秀的优化器:
    1.计算IN的结果
    2. 使用 2 的结果循环遍历每一行进行外部扫描/如果FlowId 是任何索引的第一个键,则从索引中查找结果

    糟糕的优化器(或语法限制):
    1. 遍历每一行进行外部扫描
    2. 对于每一行,计算 IN
    的结果 3. 使用2的结果计算WHERE的结果

    糟糕的情况真的很糟糕,因为它完全扫描您的表的次数与表中的行数一样多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-10
      • 2011-03-08
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 2012-09-27
      相关资源
      最近更新 更多