我知道有几个问题与此类似,但我发现这些问题与我的问题没有直接关系。
一些初步的背景:我有一个事实表,称为ft\u booking,有大约10毫米的记录。我有一个称为dm_date的维度,有大约11k条记录,即日期。这些表通常通过外键进行关联。表中有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'
如您所见,索引正在表booking中使用,查询运行得非常快,尽管在我的过滤器中,我使用的是date()函数。为简洁起见,我将使用fk\u date\u 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';
出于某种神秘的原因,计划者选择不使用索引。现在,我了解到在列上使用某些函数会迫使数据库执行完整的表扫描,以便能够在列上应用该函数,从而绕过索引。但是,在这种情况下,函数不在实际的外键列上,这是booking表中应该进行查找的地方。
如果我删除date()函数,索引将按预期用于这些列中的任何一列。有人可能会说,“那么,为什么不去掉date()函数呢?”——我使用metabase,一个允许用户使用图形界面来构建查询的界面,而不需要知道mysql,该工具当前的一个限制是,在构建非直接用mysql编写的查询时,它总是使用date()函数—因此,我无法删除正在运行的查询中的函数。
实际问题:为什么mysql在前两种情况下使用index,而在后两种情况下不使用index,因为所有列的不同值的数量几乎相同,而且除了名称之外,它们都有确切的smae定义?我是不是漏了什么?
编辑:这里是每个表的create语句。还有一些,但是我们只需要这里的表ft\u booking和dm\u date(文件的前两个表)。
1条答案
按热度按时间zlwx9yxi1#
你在“隐藏”
date
在函数调用中”。如果db.date
被宣布为DATE
,那么可以很简单
如果
db.date
被宣布为DATETIME
,然后更改为无论是哪种情况,都要确保
db.date
.如果说“我有一个称为dm\u date的维度”,您的意思是您构建了一个只包含日期的维度表,那么您就是
JOINing
在主桌上放一些id
, ... 说白了,别那么做!不要规范化“连续”的事物,例如DATE
,DATETIME
,FLOAT
,或其他数值。如果您需要进一步讨论,请提供
SHOW CREATE TABLE
有关表格(请使用文本,而不是屏幕截图。)为什么?
简单的答案是,优化器不知道如何分解任何函数。也许可以;也许应该。但事实并非如此。也许答案包括不想看到函数结果将如何被使用。。。与…相比
DATE
? 反对DATETIME
? 被用作字符串?其他的?不过,我认为真正的性能杀手是
dm_date
而不是索引和使用主表中的日期。此外,主表比它需要的大!
fk_date_booking
是4字节INT SIGNED
而不是3字节DATE
.