Interbase是一个分代数据库。
这很好,因为回滚几乎是瞬间的,但count(*)
需要永远。
这是不同于,例如MySQL, count可以使用索引。
我一直不知道为什么,直到我看到这个:
即使在COUNT中包含的一个或多个列上有索引可用,也必须访问所有记录,以查看它们在当前事务隔离下是否可见。
维基百科:http://en.wikipedia.org/wiki/InterBase
关于如何在Interbase/Firebird中进行快速计数的任何提示
根据此链接:http://www.firebirdfaq.org/faq5/
还有另一个解决方案。这个是Ivan Prenosil写的,他是Interbase和Firebird的资深黑客。此解决方案仅返回一个近似的记录计数。正如Ann W. Harrison友好地解释的那样:如果旧版本没有被垃圾收集,任何主键被修改的记录将出现两次,删除的记录将继续计数,直到它们被垃圾收集。
/* first update the statistics */ UPDATE RDB$INDICES SET RDB$STATISTICS = -1; COMMIT; /* Display table names and record counts */ SELECT RDB$RELATIONS.RDB$RELATION_NAME, CASE WHEN RDB$INDICES.RDB$STATISTICS = 0 THEN 0 ELSE CAST(1 / RDB$INDICES.RDB$STATISTICS AS INTEGER) END FROM RDB$RELATIONS LEFT JOIN RDB$RELATION_CONSTRAINTS ON RDB$RELATIONS.RDB$RELATION_NAME = RDB$RELATION_CONSTRAINTS.RDB$RELATION_NAME AND RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' LEFT JOIN RDB$INDICES ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDICES.RDB$INDEX_NAME WHERE RDB$VIEW_BLR IS NULL AND RDB$RELATION_ID >= 128 ORDER BY 1;
这只适用于有主键的表。
您也可以为要计数的表创建2个触发器。此解决方案适用于一些特殊的表,其中有很多"动作"。
CREATE TRIGGER TABLE_BI0 ACTIVE BEFORE INSERT
BEGIN
UPDATE COUNTING_TABLE
SET LINES=LINES + 1
WHERE TABLE='TABLE_NAME'; /* Table name here*/
END
CREATE TRIGGER TABLE_BD0 ACTIVE BEFORE DELETE
BEGIN
UPDATE COUNTING_TABLE
SET LINES=LINES - 1
WHERE TABLE='TABLE_NAME'; /* Table name here*/
END
之后,当您需要知道特定表的计数时,只需从COUNTING_TABLE
中选择它SELECT LINES FROM COUNTING_TABLE
WHERE TABLE='TABLE_NAME' /* Table name here*/