0

我知道有几个与此类似的问题,但我发现的问题与我的问题没有直接关系。

一些初始上下文:我有一个名为 ft_booking 的事实表,其中包含大约 10MM 条记录。我有一个名为 dm_date 的维度,有大约 11k 条记录,即日期。像往常一样,这些表通过外键关联。ft_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'

在此处输入图像描述

如您所见,在预订表中使用了索引,并且查询运行得非常快,即使在我的过滤器中,我使用的是 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';

在此处输入图像描述

出于某种神秘的原因,计划者选择不使用索引。现在,我知道在列上使用某些函数会强制数据库执行全表扫描,以便能够在列上应用该函数,从而绕过索引。但是,在这种情况下,该函数不在实际的外键列上,这是在预订表中进行查找的地方。

如果我删除 date() 函数,则索引将按预期用于任何这些列。有人可能会说,“好吧,你为什么不干脆去掉 date() 函数呢?” - 我使用元数据库,一个允许用户使用图形界面来构建查询而不了解 MySQL 的界面,该工具的当前限制之一是它在构建不直接写入的查询时总是使用 date() 函数MySQL - 因此,我无法删除正在运行的查询中的函数。

实际问题:为什么 MySQL 在前两种情况下使用索引,但在后一种情况下不使用,考虑到所有列的不同值的数量几乎相同,并且它们具有确切的 smae 定义,除了名称?我在这里错过了什么吗?

编辑:是所涉及的每个表的 CREATE 语句。还有更多,但我们这里只需要 ft_booking 和 dm_date 表(文件的前两个表)。

4

1 回答 1

1

您正在“隐藏date在函数调用中”。如果db.date声明为 a DATE,则

    date (db.date) = '2018-05-05'

可以很简单

    db.date = '2018-05-05'

如果db.date声明为 a DATETIME,则更改为

        db.date >= '2018-05-05'
    AND db.date  < '2018-05-05' + INTERVAL 1 DAY

在任何一种情况下,请确保在db.date.

如果通过“我有一个名为 dm_date 的维度”,您的意思是您构建了一个维度表来仅保存日期,然后您将JOINing进入主表,其中包含一些id, ... 坦率地说,不要那样做! 不要规范化“连续”事物,例如DATEDATETIMEFLOAT或其他数值。

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

为什么??

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

尽管如此,我认为真正的性能杀手是存在dm_date而不是索引和使用主表中的日期。

此外,主表比它需要的大! fk_date_booking是 4-byteINT SIGNED而不是 3-byte DATE

于 2018-06-08T22:46:21.223 回答