【问题标题】:Mysql index useMysql索引使用
【发布时间】:2015-02-17 10:29:58
【问题描述】:

我有 2 个带有公共字段的表。在一张表上,公共字段有一个索引 而另一方面不是。运行如下查询:

SELECT * 
FROM table_with_index
LEFT JOIN table_without_index ON table_with_index.comcol = table_without_index.comcol
WHERE 1

查询的性能比运行相反的要差:

SELECT * 
FROM table_without_index 
LEFT JOIN table_with_indexON table_without_index.comcol = table_with_index.comcol 
WHERE 1

谁能解释我为什么以及在这种情况下使用索引背后的逻辑?

【问题讨论】:

  • 没有区别。优化器应该选择最快的方式来执行查询,不管你用哪种方式指定连接条件。
  • 您正在从表中选择所有行,因此索引表会更快。如果它是 INNER JOIN 则无关紧要。
  • @jarlh INNER JOINs 没有区别。在LEFT JOINs 上,优化器无法交换表。
  • @axiac,抱歉,没有仔细阅读。

标签: mysql sql performance database-indexes


【解决方案1】:

您可以在查询前添加EXPLAIN,以了解 MySQL 将如何使用索引以及它将以何种顺序加入表。

查看EXPLAIN output format 的文档以了解如何解释结果。

因为LEFT JOINs,表格的顺序不能改变。 MySQL 需要在最终结果集中包含左表中的所有行,无论它们在右表中是否匹配。

INNER JOINs 上,MySQL 通常会交换表并将行数较少的表放在首位,因为这样它需要分析的行数较少。

让我们来看看这个查询(这是您的查询,表的名称较短):

SELECT *
FROM a
  LEFT JOIN b ON a.col = b.col
WHERE 1

MySQL 如何运行此查询:

  1. 它从表a 中获取与查询条件匹配的第一行。如果 WHERE 或 join 子句中存在仅使用表 a 的字段和常量值的条件,则使用包含部分或全部这些字段的索引来仅过滤与条件匹配的行。

  2. 从表a 中选择一行后,它会转到执行计划中的下一个表(这是我们查询中的表b)。它必须选择与WHERE 条件和JOIN 条件匹配的所有行。更具体地说,从表b 中选择的行必须与条件b.col = X 匹配,其中X 是在步骤1 中当前从表a 中选择的行的列col 的值。它找到第一个匹配的行然后转到下一个表。由于此查询中没有“下一个表”,因此它将这对行(来自ab)放入结果集中,然后丢弃来自b 的行并搜索下一个,重复此操作直到找到b 中与当前从a 中选择的行匹配的所有行(在第1 步中)。

  3. 如果在步骤 2 中无法从 b 中找到与当前从 a 中选择的行匹配的任何行,则 LEFT JOIN 会强制 MySQL 将一行(具有 b 的列)填满NULLs 和 a 中的当前行一起创建一个行并将其放入结果集中。

  4. 处理完来自b 的所有匹配行后,MySQL 会丢弃来自a 的当前行,从a 中选择与WHERE 和连接条件匹配的下一行,并从从b 中选择匹配的行(步骤 2)。

  5. 此过程循环,直到a 中的所有行都已处理完毕。

备注:

  • 第 1 步中“第一行”的含义取决于很多因素。例如,如果表a 上的索引包含查询中指定的所有列(表a),那么MySQL 将不会读取表数据,而是使用索引。在这种情况下,行的顺序由索引给出。在其他情况下,行是从表数据中读取的,并且顺序由它们在存储介质上的存储顺序提供。

    这个简单的查询没有任何WHERE 条件(WHERE 1 始终为 TRUE),而且JOIN 子句中也没有条件,它只包含来自a 的列。表a 中的所有行都包含在结果集中,这会导致full table scan 或索引扫描(如果可能)。

  • 1234563这是一个快速的操作。如果表b 在列col 上没有索引,那么MySQL 需要执行表bfull table scan。这意味着它必须读取表b所有行,才能在col 列上找到具有X 值的行。这是一个非常缓慢且耗费资源的操作。
  • 由于表a的行没有条件,MySQL不能使用表a的索引来过滤它选择的行。另一方面,当它需要从表 b 中选择行时(在步骤 2 中),它有一个匹配的条件 (b.col = X),它可以使用索引来加快选择速度,给定这样的索引存在于表b

这解释了两个查询之间性能的巨大差异。此外,由于LEFT JOIN,您的两个查询并不等价,它们会产生不同的结果。

免责声明:请注意,上述步骤列表是对查询执行工作原理的过于简化的解释。它试图用简单的语言来表达,并跳过幕后发生的许多技术方面。

有关如何使查询运行得更快的提示可以在 MySQL 文档8. Optimization 部分找到

【讨论】:

    【解决方案2】:

    要检查 MySQL 查询优化器的情况,请显示这两个查询的 EXPLAIN 计划。是这样的:

    EXPLAIN 
    SELECT * FROM table_with_index
    LEFT JOIN table_without_index ON table_with_index.comcol =       table_without_index.comcol
    WHERE 1
    

    EXPLAIN
    SELECT * 
    FROM table_without_index 
    LEFT JOIN table_with_indexON table_without_index.comcol = table_with_index.comcol 
    WHERE 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-17
      • 2018-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-29
      • 2010-12-13
      • 2011-03-24
      相关资源
      最近更新 更多