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" 诸如 DATEDATETIME 之类的东西, FLOAT, 或其他数值。

如果您需要进一步讨论,请为相关 table(s) 提供 SHOW CREATE TABLE。 (请使用文字,而不是屏幕截图。)

为什么?

简单的回答是优化器不知道如何解开任何函数。也许可以;也许应该。但事实并非如此。也许答案是不想看到函数结果将如何使用……与 DATE 进行比较?反对DATETIME?被用作字符串?其他?

不过,我建议真正的性能杀手是 dm_date 的存在,而不是在主 table.

中索引和使用日期

此外,主 table 比需要的要大! fk_date_booking 是 4 字节的 INT SIGNED 而不是 3 字节的 DATE.