MySQL 连接时的索引使用情况
MySQL index usage on join
我知道有几个问题与此类似,但我发现的问题与我的问题没有直接关系。
一些初始上下文:我有一个事实 table,称为 ft_booking,有大约 10MM 的记录。我有一个名为 dm_date 的维度,其中包含大约 11k 条记录,这些记录是日期。这些 table 像往常一样通过外键关联。 tableft_booking中有3个日期外键,一个是登机的,一个是预订的,一个是取消的。所有列都具有完全相同的定义,并且每个列的不同记录数量相似(每列中的不同值从 2.5k 到 3k 不等)。
我走了:
EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_booking
WHERE date (db.date) = '2018-05-05'
如您所见,table 预订中使用了索引,并且查询运行得非常快,尽管在我的过滤器中,我使用的是 date() 函数。为简洁起见,我将仅声明使用 fk_date_boarding 列也会发生同样的情况。但是,看看这个:
EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_cancellation
WHERE date (db.date) = '2018-05-05';
出于某种神秘原因,规划者选择不使用索引。现在,我明白在列上使用某些函数会强制数据库执行完整的 table 扫描,以便能够在列上应用该函数,从而绕过索引。但是,在这种情况下,函数不在实际的外键列上,预订 table 中的查找应该发生在该列上。
如果我删除 date() 函数,索引将按预期用于任何这些列。那么有人可能会说,"well, why don't you just get rid of the date() function?" - 我使用元数据库,这是一种允许用户使用图形界面构建查询的界面,而无需知道 MySQL,该工具当前的限制之一是在构建未直接写入 MySQL 的查询时,它总是使用 date() 函数 - 因此,我无法删除我是 运行.
的查询中的函数
实际问题:为什么 MySQL 在前两种情况下使用索引,而在后一种情况下不使用索引,考虑到所有列的不同值的数量几乎相同并且它们具有确切的smae 定义,除了名字?我在这里遗漏了什么吗?
编辑:Here 是涉及的每个 table 的 CREATE 语句。还有一些,但我们只需要这里 tables ft_booking 和 dm_date (文件的前两个 tables)。
你是"hiding date
in a function call"。如果 db.date
声明为 DATE
,则
date (db.date) = '2018-05-05'
可以简单
db.date = '2018-05-05'
如果 db.date
声明为 DATETIME
,则更改为
db.date >= '2018-05-05'
AND db.date < '2018-05-05' + INTERVAL 1 DAY
无论哪种情况,请确保 db.date
.
上有索引
如果 "I have a dimension called dm_date",你的意思是你建立了一个维度 table 来保存日期,然后你 JOINing
到主要的 table 和一些 id
, ... 坦率地说,不要那样做! 不要规范化 "continuous" 诸如 DATE
、DATETIME
之类的东西, FLOAT
, 或其他数值。
如果您需要进一步讨论,请为相关 table(s) 提供 SHOW CREATE TABLE
。 (请使用文字,而不是屏幕截图。)
为什么?
简单的回答是优化器不知道如何解开任何函数。也许可以;也许应该。但事实并非如此。也许答案是不想看到函数结果将如何使用……与 DATE
进行比较?反对DATETIME
?被用作字符串?其他?
不过,我建议真正的性能杀手是 dm_date
的存在,而不是在主 table.
中索引和使用日期
此外,主 table 比需要的要大! fk_date_booking
是 4 字节的 INT SIGNED
而不是 3 字节的 DATE
.
我知道有几个问题与此类似,但我发现的问题与我的问题没有直接关系。
一些初始上下文:我有一个事实 table,称为 ft_booking,有大约 10MM 的记录。我有一个名为 dm_date 的维度,其中包含大约 11k 条记录,这些记录是日期。这些 table 像往常一样通过外键关联。 tableft_booking中有3个日期外键,一个是登机的,一个是预订的,一个是取消的。所有列都具有完全相同的定义,并且每个列的不同记录数量相似(每列中的不同值从 2.5k 到 3k 不等)。
我走了:
EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_booking
WHERE date (db.date) = '2018-05-05'
如您所见,table 预订中使用了索引,并且查询运行得非常快,尽管在我的过滤器中,我使用的是 date() 函数。为简洁起见,我将仅声明使用 fk_date_boarding 列也会发生同样的情况。但是,看看这个:
EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_cancellation
WHERE date (db.date) = '2018-05-05';
出于某种神秘原因,规划者选择不使用索引。现在,我明白在列上使用某些函数会强制数据库执行完整的 table 扫描,以便能够在列上应用该函数,从而绕过索引。但是,在这种情况下,函数不在实际的外键列上,预订 table 中的查找应该发生在该列上。
如果我删除 date() 函数,索引将按预期用于任何这些列。那么有人可能会说,"well, why don't you just get rid of the date() function?" - 我使用元数据库,这是一种允许用户使用图形界面构建查询的界面,而无需知道 MySQL,该工具当前的限制之一是在构建未直接写入 MySQL 的查询时,它总是使用 date() 函数 - 因此,我无法删除我是 运行.
的查询中的函数实际问题:为什么 MySQL 在前两种情况下使用索引,而在后一种情况下不使用索引,考虑到所有列的不同值的数量几乎相同并且它们具有确切的smae 定义,除了名字?我在这里遗漏了什么吗?
编辑:Here 是涉及的每个 table 的 CREATE 语句。还有一些,但我们只需要这里 tables ft_booking 和 dm_date (文件的前两个 tables)。
你是"hiding date
in a function call"。如果 db.date
声明为 DATE
,则
date (db.date) = '2018-05-05'
可以简单
db.date = '2018-05-05'
如果 db.date
声明为 DATETIME
,则更改为
db.date >= '2018-05-05'
AND db.date < '2018-05-05' + INTERVAL 1 DAY
无论哪种情况,请确保 db.date
.
如果 "I have a dimension called dm_date",你的意思是你建立了一个维度 table 来保存日期,然后你 JOINing
到主要的 table 和一些 id
, ... 坦率地说,不要那样做! 不要规范化 "continuous" 诸如 DATE
、DATETIME
之类的东西, FLOAT
, 或其他数值。
如果您需要进一步讨论,请为相关 table(s) 提供 SHOW CREATE TABLE
。 (请使用文字,而不是屏幕截图。)
为什么?
简单的回答是优化器不知道如何解开任何函数。也许可以;也许应该。但事实并非如此。也许答案是不想看到函数结果将如何使用……与 DATE
进行比较?反对DATETIME
?被用作字符串?其他?
不过,我建议真正的性能杀手是 dm_date
的存在,而不是在主 table.
此外,主 table 比需要的要大! fk_date_booking
是 4 字节的 INT SIGNED
而不是 3 字节的 DATE
.