我知道有几个与此类似的问题,但我发现的问题与我的问题没有直接关系。
一些初始上下文:我有一个名为 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 表(文件的前两个表)。