MySQL查询索引

MySQL query index

我正在使用 MySQL 5.6 并尝试优化下一个查询:

SELECT t1.field1,
       ...
       t1.field30,
       t2.field1
FROM Table1 t1
         JOIN Table2 t2 ON t1.fk_int = t2.pk_int
WHERE t1.int_field = ?
  AND t1.enum_filed != 'value'
ORDER BY t1.created_datetime desc;

一个响应可以包含数百万条记录,每行包含 31 列。

现在 EXPLAIN 在 Extra 中说规划器使用 'Using where'。

我尝试添加下一个索引:

create index test_idx ON Table1 (int_field, enum_filed, created_datetime, fk_int);

在那之后 EXPLAIN 在 Extra 中说规划器使用“使用索引条件;使用文件排序”

带有索引的 EXPLAIN 中的“行”值小于没有它的情况。但实际上执行时间更长。

所以,接下来的问题是:

  1. 这个查询的最佳索引是什么?
  2. 为什么EXPLAIN说'key_len' of query with index是5,不应该是4+1+8+4=17吗?
  3. ORDER BY 中的字段应该在索引中吗?
  4. JOIN 中的字段应该在索引中吗?

尝试以这种方式重构您的索引
避免(o 在 fk_int 之后向右移动)created_datetime 列 .. 并在 enum_filed 列之前移动 fk_int .. 在这种情况下,还有 3 个列用于过滤器应该更好用)

create index test_idx ON Table1 (int_field, fk_int, enum_filed);

确保您在 table2 列 pk_int 上也有一个特定索引。如果你还没有添加

create index test_idx ON Table2 (int_field, fk_int, enum_filed);

我对第 1 个问题的猜测:

create index my_idx on Table1(int_field, created_datetime desc, fk_int)

或其中之一(但可能都不值得):

create index my_idx on Table1(int_field, created_datetime desc, enum_filed, fk_int)
create index my_idx on Table1(int_field, created_datetime desc, fk_int, enum_filed)

我假设 3 件事:

  • Table2.pk_int已经是主键了,根据名字判断
  • Table1.int_field 上的 where 条件只有 Table1
  • 的一小部分满足
  • Table1.enum_filed 上的不等式(如果我是你,我会改正错字)只排除了 Table1
  • 的一小部分

问题 № 2: key_len 指的是使用的键。不要忘记可空键有一个额外的字节。在您的情况下,如果 int_field 可以为空,则意味着这是唯一使用的键,否则 int_fieldenum_filed 都被使用。

至于问题3和4:如果像我想的那样,从Table1.int_fieldwhere条件开始查询计划效率更高,复合索引,在这种情况下也有正确的排序顺序 (desc),使索引扫描能够以正确的顺序获取输出行,而无需额外的排序步骤。此外,将 fk_int 也添加到索引使得检索 Table1 的任何记录变得不必要 除非 Table2 中存在相应的记录。出于类似的原因,您也可以将 enum_filed 添加到索引,但是,如果这没有显着减少输出记录数,索引大小的增加将使事情变得更糟而不是更好。最后,您将不得不尝试一下(使用真实数据!)。

请注意,如果您在索引中的 int_fieldcreated_datetime 之间放置另一列,索引将不会提供 created_datetime(对于给定的 int_field)按所需的输出顺序。

这个查询的最佳索引是什么?

  • 也许(int_field, created_datetime)(原因请看下一个问答。)

为什么EXPLAIN说'key_len' of query with index是5,不应该是4+1+8+4=17吗?

  • enum_filed != 打败了优化器。如果该枚举只有一个其他值(并且是 NOT NULL),则使用 = 和另一个值。并尝试 INDEX(int_field, enum_field, created_datetime) 与任何不等式相比,优化器对 = 更满意。
  • “5”可能表示 2 列,也可能表示一个 INT 可以为 Nullable。如果int_field可以NULL,考虑改成NOT NULL;然后“5”会下降到“4”。

ORDER BY 中的字段应该在索引中吗?

  • 只有索引可以完全处理 WHERE。这通常仅在所有 WHERE 测试都是 = 时才会发生。 (因此,我之前的回答。)
  • 包含这些列的另一种情况是“覆盖”;请参阅下一个问答。

JOIN 中的字段应该在索引中吗?

  • 视情况而定。提供 一些 性能优势的一件事是在 SELECT.这称为“覆盖”索引,在 EXPLAIN 中由 Using index(而非 Using index condition)表示。 t1 中的列太多,无法添加“覆盖”索引。我认为实际限制是大约 5 列。

通过向查询添加更多过滤器(where 子句)解决了该问题。 关于索引,建议的 2 个索引有帮助:

  1. 来自@WalterTross 初始查询的下一个索引:

(int_field, created_datetime desc, enum_filed, fk_int)

我的简短评论:MySQL 5.6 不支持 desc 索引 - 这个关键字只是保留的。

  1. 来自@RickJames,修改查询的下一个索引:

(int_field, created_datetime)

感谢所有试图提供帮助的人。非常感谢。