我正在使用 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/