Mysql 索引使用
Mysql index use
我有 2 个 table 有共同的领域。在一个 table 上,公共字段有一个索引
而另一方面没有。 运行 查询如下:
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
任何人都可以向我解释为什么以及在这种情况下使用索引背后的逻辑?
要检查 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
您可以在查询前添加 EXPLAIN
以了解 MySQL 将如何使用索引以及它加入 table 的顺序。
查看 EXPLAIN
output format 的文档,了解如何解释结果。
因为LEFT JOIN
的缘故,table的顺序不能改变。 MySQL 需要在最终结果集中包括从左侧 table 开始的所有行,无论它们是否在右侧 table.
中有匹配项
在 INNER JOIN
s 上,MySQL 通常交换 tables 并将行数较少的 table 放在第一位,因为这样它的行数较少分析。
我们来看这个查询(这是您的 table 名称较短的查询):
SELECT *
FROM a
LEFT JOIN b ON a.col = b.col
WHERE 1
如何MySQL 运行查询:
获取tablea
中符合查询条件的第一行。如果 WHERE
或连接子句中的条件仅使用 table a
的字段和常量值,则包含部分或全部这些字段的索引仅用于过滤行符合条件。
在 table a
的一行被 select 编辑后,它转到执行计划中的下一个 table (这是 table b
在我们的查询中)。它必须 select 所有符合 WHERE
条件和 JOIN
条件的行。更具体地说,从 table b
编辑的 select 行必须匹配条件 b.col = X
,其中 X
是列 col
的值对于当前从步骤 1 table a
编辑的行 select。它找到第一个匹配行,然后转到下一个 table。由于此查询中没有 "next table",它会将一对行(来自 a
和 b
)放入结果集中,然后丢弃来自 b
的行并搜索对于下一个,重复此步骤,直到找到 b
中与当前 select 从 a
编辑的行匹配的所有行(在步骤 1 中)。
如果在第 2 步中找不到 b
中与当前 select 从 a
编辑的行相匹配的任何行,则 LEFT JOIN
强制 MySQL 组成一行(具有 b
的列),其中包含 NULL
s 并与来自 a
的当前行一起创建一行并将其放入结果集中.
处理完来自 b
的所有匹配行后,MySQL 丢弃来自 a
的当前行,select 丢弃来自 select 的下一行a
匹配 WHERE
和连接条件,并从 b
中匹配行的 selection 重新开始(步骤 2)。
此过程循环进行,直到处理完 a
中的所有行。
备注:
步骤 1 中 "first row" 的含义取决于很多因素。例如,如果 table a
上有一个索引包含查询中指定的所有列(属于 table a
),则 MySQL 将不会读取table 数据,但将改用索引。在这种情况下,行的顺序由索引给出。在其他情况下,行是从 table 数据中读取的,顺序由它们存储在存储介质上的顺序提供。
这个简单的查询没有任何 WHERE
条件(WHERE 1
总是 TRUE)并且 JOIN
子句中没有条件只包含来自 a
。 table a
中的所有行都包含在结果集中,如果可能的话,这会导致 full table scan 或索引扫描。
在第 2 步中,如果 table b
在列 col
上有索引,则 MySQL 使用该索引从 b
在列 col
上具有值 X
。这是一个快速的操作。如果 table b
在列 col
上没有索引,则 MySQL 需要执行 table b
的 full table scan
。这意味着它必须读取 table b
的所有行 才能找到那些在列 col
上具有值 X
的行。这是一个非常缓慢且耗费资源的操作。
因为tablea
的行没有条件,MySQL不能用tablea
的索引来过滤它 selects 的行。另一方面,当它需要 select 来自 table b
的行时(在第 2 步),它有一个匹配条件 (b.col = X
) 并且它可以使用加速 selection 的索引,假设这样的索引存在于 table b
.
这解释了您的两个查询之间的巨大性能差异。此外,由于 LEFT JOIN
,您的两个查询不等价,它们产生不同的结果。
免责声明: 请注意,上面的步骤列表是对查询执行方式的过度简化说明。它试图用简单的语言来表达,并跳过幕后发生的许多技术方面。
有关如何使查询 运行 更快的提示可以在 MySQL 文档的 8. Optimization
部分找到
我有 2 个 table 有共同的领域。在一个 table 上,公共字段有一个索引 而另一方面没有。 运行 查询如下:
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
任何人都可以向我解释为什么以及在这种情况下使用索引背后的逻辑?
要检查 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
您可以在查询前添加 EXPLAIN
以了解 MySQL 将如何使用索引以及它加入 table 的顺序。
查看 EXPLAIN
output format 的文档,了解如何解释结果。
因为LEFT JOIN
的缘故,table的顺序不能改变。 MySQL 需要在最终结果集中包括从左侧 table 开始的所有行,无论它们是否在右侧 table.
在 INNER JOIN
s 上,MySQL 通常交换 tables 并将行数较少的 table 放在第一位,因为这样它的行数较少分析。
我们来看这个查询(这是您的 table 名称较短的查询):
SELECT *
FROM a
LEFT JOIN b ON a.col = b.col
WHERE 1
如何MySQL 运行查询:
获取table
a
中符合查询条件的第一行。如果WHERE
或连接子句中的条件仅使用 tablea
的字段和常量值,则包含部分或全部这些字段的索引仅用于过滤行符合条件。在 table
a
的一行被 select 编辑后,它转到执行计划中的下一个 table (这是 tableb
在我们的查询中)。它必须 select 所有符合WHERE
条件和JOIN
条件的行。更具体地说,从 tableb
编辑的 select 行必须匹配条件b.col = X
,其中X
是列col
的值对于当前从步骤 1 tablea
编辑的行 select。它找到第一个匹配行,然后转到下一个 table。由于此查询中没有 "next table",它会将一对行(来自a
和b
)放入结果集中,然后丢弃来自b
的行并搜索对于下一个,重复此步骤,直到找到b
中与当前 select 从a
编辑的行匹配的所有行(在步骤 1 中)。如果在第 2 步中找不到
b
中与当前 select 从a
编辑的行相匹配的任何行,则LEFT JOIN
强制 MySQL 组成一行(具有b
的列),其中包含NULL
s 并与来自a
的当前行一起创建一行并将其放入结果集中.处理完来自
b
的所有匹配行后,MySQL 丢弃来自a
的当前行,select 丢弃来自 select 的下一行a
匹配WHERE
和连接条件,并从b
中匹配行的 selection 重新开始(步骤 2)。此过程循环进行,直到处理完
a
中的所有行。
备注:
步骤 1 中 "first row" 的含义取决于很多因素。例如,如果 table
a
上有一个索引包含查询中指定的所有列(属于 tablea
),则 MySQL 将不会读取table 数据,但将改用索引。在这种情况下,行的顺序由索引给出。在其他情况下,行是从 table 数据中读取的,顺序由它们存储在存储介质上的顺序提供。这个简单的查询没有任何
WHERE
条件(WHERE 1
总是 TRUE)并且JOIN
子句中没有条件只包含来自a
。 tablea
中的所有行都包含在结果集中,如果可能的话,这会导致 full table scan 或索引扫描。在第 2 步中,如果 table
b
在列col
上有索引,则 MySQL 使用该索引从b
在列col
上具有值X
。这是一个快速的操作。如果 tableb
在列col
上没有索引,则 MySQL 需要执行 tableb
的full table scan
。这意味着它必须读取 tableb
的所有行 才能找到那些在列col
上具有值X
的行。这是一个非常缓慢且耗费资源的操作。因为table
a
的行没有条件,MySQL不能用tablea
的索引来过滤它 selects 的行。另一方面,当它需要 select 来自 tableb
的行时(在第 2 步),它有一个匹配条件 (b.col = X
) 并且它可以使用加速 selection 的索引,假设这样的索引存在于 tableb
.
这解释了您的两个查询之间的巨大性能差异。此外,由于 LEFT JOIN
,您的两个查询不等价,它们产生不同的结果。
免责声明: 请注意,上面的步骤列表是对查询执行方式的过度简化说明。它试图用简单的语言来表达,并跳过幕后发生的许多技术方面。
有关如何使查询 运行 更快的提示可以在 MySQL 文档的 8. Optimization
部分找到