过去几个月我一直在使用 Firebird,今天一位客户抱怨性能问题。
我检查了客户的数据库,他们在一张表中有 167,77,216 行。因此,我将该表克隆到另一个空数据库中,并加载虚拟记录并使用简单的查询进行测试
select count(journal_id) from acc_journal
Run Code Online (Sandbox Code Playgroud)
花了14.28秒。
之后我创建了一个 SQLite 数据库并加载了这些数据,花了 2.216 秒。
这是 Firebid 的本质还是我错过了什么?
火鸟表结构:
CREATE TABLE ACC_JOURNAL (
JOURNAL_ID INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
ACCOUNT_HEAD_ID INTEGER,
REF_ID INTEGER,
REF_TYPE VARCHAR(20),
DESCRIPTION VARCHAR(512),
DEBIT DECIMAL(18,4),
DEBIT_EX DECIMAL(18,4),
CREDIT DECIMAL(18,4),
CREDIT_EX DECIMAL(18,4),
CURRENCY_ID INTEGER,
STATUS VARCHAR(20),
EX_RATE DECIMAL(18,4),
ENTRY_DATE VARCHAR(20),
ENTRY_TIME VARCHAR(20),
BRANCH_CODE VARCHAR(20),
LAST_SYNCED VARCHAR(20),
LAST_UPDATED DECIMAL(18,4),
ENTRY_DATE2 VARCHAR(20),
/* Keys */
PRIMARY KEY (JOURNAL_ID)
);
Run Code Online (Sandbox Code Playgroud)
SQLite表结构:
CREATE TABLE ACC_JOURNAL (
ACCOUNT_HEAD_ID INTEGER,
REF_ID INTEGER,
REF_TYPE VARCHAR (20),
DESCRIPTION VARCHAR (512),
DEBIT DECIMAL (18, 4),
DEBIT_EX DECIMAL (18, 4),
CREDIT DECIMAL (18, 4),
CREDIT_EX DECIMAL (18, 4),
CURRENCY_ID INTEGER,
STATUS VARCHAR (20),
EX_RATE DECIMAL (18, 4),
ENTRY_DATE VARCHAR (20),
ENTRY_TIME VARCHAR (20),
BRANCH_CODE VARCHAR (20),
LAST_SYNCED VARCHAR (20),
LAST_UPDATED DECIMAL (18, 4),
ENTRY_DATE2 VARCHAR (20),
JOURNAL_ID INTEGER PRIMARY KEY AUTOINCREMENT
);
Run Code Online (Sandbox Code Playgroud)
不幸的是,这是因为 Firebird 必须进行全表扫描才能获取计数。我不熟悉 SQLite 的工作原理,但快速搜索似乎表明 SQLite 可以使用索引来获取计数(例如,count(*)
如果使用 ,则使用主键索引或列上的索引count(columnname)
,尽管我还没有验证这是否实际上是正确的)。
Firebird之所以需要进行全表扫描,是因为Firebird是一个MVCC(多版本并发控制)数据库,但记录可见性信息不包含在其索引中。因此,为了能够知道记录对您的交易可见并因此应包含在计数中,Firebird 需要读取实际记录。而且由于查询是无条件计数,因此使用索引然后检查每条记录会比仅读取每条记录慢。
但是,您可以采取一些措施来提高性能:
使用count(*)
而不是count(journal_id)
.
使用count(*)
只会计算记录,而会计算不为空的count(journal_id)
记录。journal_id
Firebird 不使用not null
主键的状态,因此它会检查每条记录的该列是否不为空。在我的系统上,更改为可count(*)
将查询时间减少大约 25%。
使用更大的页面尺寸。
您的示例数据库的页面大小为 4096,将其增加到页面大小 16384 可以将示例查询(使用count(journal_id)
)的执行时间减少大约 20%,而count(*)
(与页面大小 4096 上的原始查询相比)减少更多超过50%。
然而,鉴于无条件的整体性能较差count
,主要建议是避免使用无条件count
。