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 中的“行”值小于没有它的情况。但实际上执行时间更长。
所以,接下来的问题是:
- 这个查询的最佳索引是什么?
- 为什么EXPLAIN说'key_len' of query with index是5,不应该是4+1+8+4=17吗?
- ORDER BY 中的字段应该在索引中吗?
- 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_field
和 enum_filed
都被使用。
至于问题3和4:如果像我想的那样,从Table1.int_field
的where
条件开始查询计划效率更高,复合索引,在这种情况下也有正确的排序顺序 (desc
),使索引扫描能够以正确的顺序获取输出行,而无需额外的排序步骤。此外,将 fk_int
也添加到索引使得检索 Table1
的任何记录变得不必要 除非 在 Table2
中存在相应的记录。出于类似的原因,您也可以将 enum_filed
添加到索引,但是,如果这没有显着减少输出记录数,索引大小的增加将使事情变得更糟而不是更好。最后,您将不得不尝试一下(使用真实数据!)。
请注意,如果您在索引中的 int_field
和 created_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 个索引有帮助:
- 来自@WalterTross 初始查询的下一个索引:
(int_field, created_datetime desc, enum_filed, fk_int)
我的简短评论:MySQL 5.6 不支持 desc 索引 - 这个关键字只是保留的。
- 来自@RickJames,修改查询的下一个索引:
(int_field, created_datetime)
感谢所有试图提供帮助的人。非常感谢。
我正在使用 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 中的“行”值小于没有它的情况。但实际上执行时间更长。
所以,接下来的问题是:
- 这个查询的最佳索引是什么?
- 为什么EXPLAIN说'key_len' of query with index是5,不应该是4+1+8+4=17吗?
- ORDER BY 中的字段应该在索引中吗?
- 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_field
和 enum_filed
都被使用。
至于问题3和4:如果像我想的那样,从Table1.int_field
的where
条件开始查询计划效率更高,复合索引,在这种情况下也有正确的排序顺序 (desc
),使索引扫描能够以正确的顺序获取输出行,而无需额外的排序步骤。此外,将 fk_int
也添加到索引使得检索 Table1
的任何记录变得不必要 除非 在 Table2
中存在相应的记录。出于类似的原因,您也可以将 enum_filed
添加到索引,但是,如果这没有显着减少输出记录数,索引大小的增加将使事情变得更糟而不是更好。最后,您将不得不尝试一下(使用真实数据!)。
请注意,如果您在索引中的 int_field
和 created_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 个索引有帮助:
- 来自@WalterTross 初始查询的下一个索引:
(int_field, created_datetime desc, enum_filed, fk_int)
我的简短评论:MySQL 5.6 不支持 desc 索引 - 这个关键字只是保留的。
- 来自@RickJames,修改查询的下一个索引:
(int_field, created_datetime)
感谢所有试图提供帮助的人。非常感谢。