使用JOIN时不使用Firebird索引,为什么?

标签 firebird firebird2.5

我正在使用 FB 2.5.5,我试图理解为什么一个非常简单的查询不使用索引,因此需要永远执行。我读过很多关于为什么查询优化器可能会忽略现有索引的文章,但我不明白在我的情况下它是如何发生的。我重新计算了 IB Expert 中所有索引的选择性,并且还对数据库进行了备份/恢复,以确保我没有遗漏任何内容。

根据 IB Expert 显示,索引选择性约为 0,000024 - 远非 1:

CREATE INDEX TVERSIONS_IDX_LASTMODDATE ON TVERSIONS (LASTMODDATE)

我正在查询的表包含大约。 2M 条记录:

SELECT COUNT(ID) FROM TVERSIONS
2479518

我正在尝试根据 LASTMODDATE 字段(TIMETSAMP,由 TVERSIONS_IDX_LASTMODDATE 索引)获取所有记录。查询的过于简化的版本是:

SELECT COUNT(ID) FROM TVERSIONS WHERE LASTMODDATE > :TheDate

在这种情况下,执行计划显示实际使用了索引:

Plan
PLAN (TVERSIONS INDEX (TVERSIONS_IDX_LASTMODDATE))

...并且可以非常快速地获取符合条件的记录:

------ Performance info ------
Prepare time = 172ms
Execute time = 16ms <----
Avg fetch time = 16,00 ms
Current memory = 2 714 672
Max memory = 10 128 480
Memory buffers = 90
Reads from disk to cache = 57
Writes from cache to disk = 0
Fetches from cache = 387

现在,“真实”查询在 LASTMODDATE 上使用相同条件获取相同字段,但添加了 3 个表的 JOIN :

SELECT COUNT(ID) FROM TVERSIONS
    JOIN TFILES ON TFILES.ID = TVERSIONS.FILEID
    JOIN TROOTS ON TROOTS.ID = TFILES.ROOTID
    JOIN TUSERSBACKUPS ON TROOTS.BACKUPID = TUSERSBACKUPS.BACKUPID
    WHERE TUSERSBACKUPS.USERID= :UserID
    AND TVERSIONS.LASTMODDATE >:TheDate

现在查询计划不再使用索引:

Plan
PLAN JOIN (TUSERSBACKUPS INDEX (RDB$FOREIGN4), TROOTS INDEX (RDB$FOREIGN3), TFILES INDEX (RDB$FOREIGN2), TVERSIONS INDEX (RDB$FOREIGN6))

毫无疑问,执行时间慢得多(大约 1 分钟):

------ Performance info ------
Prepare time = 329ms
Execute time = 53s 593ms <---
Avg fetch time = 53 593,00 ms
Current memory = 3 044 736
Max memory = 10 128 480
Memory buffers = 90
Reads from disk to cache = 55 732
Writes from cache to disk = 0
Fetches from cache = 6 952 648

换句话说,搜索整个表比搜索 JOIN 返回的行子集要快得多。

我不明白为什么仅仅因为我添加了 join 子句就不再使用 LASTMODDATE 字段上的索引。索引的选择性好,查询也很简单。我错过了什么?

最佳答案

Firebird 似乎决定使用索引 RDB$FOREIGN4 以条件 TUSERSBACKUPS.USERID=:UserID 开始。可能会发生这种情况,因为您在这里具有相等性,并且对于条件 TVERSIONS.LASTMODDATE >:TheDate 您具有不等式,这可能会导致潜在的更大的记录集(例如,如果 TheDate 是200 年前的日期,它将包括整个表格)。

要强制 Firebird 使用您(但不是其优化器)喜欢的计划 - 使用 PLAN 子句,请参阅 http://www.firebirdfaq.org/faq224/

关于使用JOIN时不使用Firebird索引,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35508540/

相关文章:

sql - 有条件的 where 子句导致 Firebird 的性能很差

sql - 返回根据字段值重复的记录

sql - 使用保留字时间戳作为字段名称 (Firebird 2.5)

c# - 尝试在 Visual Studio 中连接到 Firebird 时出现访问被拒绝错误

entity-framework-6 - Visual Studio 2013 教授中的 Entity Framework 6/Firebird 数据库提供程序兼容性问题

sql - 分组中的字符串连接

sql - Firebird 触发 SQL 验证查询

mysql - 查询 firebird slow order by/distinct

mysql - 从 Firebird 数据库连接到 MySQL 数据库

sql - 在 Firebird DB 中创建外键时出错