我在Firebird数据库上执行缓慢的INSERT语句时遇到问题。绩效值如下:
使用Windows XP在笔记本电脑上插入3800条记录大约需要31秒(每秒约120次插入)。在Windows 7 32位的另一台PC上,同样的任务需要80秒(每秒约50次插入)!从2011年10月开始使用的Firebird版本是2.5.1 SuperServer。使用的连接技术是DBExpress。
这就是我的数据库表的创建方式:
CREATE TABLE RESULTS
(
POS INTEGER,
FIELD_CODE VARCHAR(255),
FIELD_DESC VARCHAR(255),
ORD INTEGER,
RVALUE VARCHAR(2048),
DETAIL VARCHAR(2048)
);
这是访问它的源代码。与现实相比,它有点简化(不包括调用者方法),但确实包括所有基本的东西。 Profiler表明这种特殊方法是瓶颈。一次调用需要大约10毫秒。所以3800个电话需要大约38秒。
Field *field = NULL;
int ord = GetFieldOrder(field_code, &field);
if (field == NULL)
{
return -1;
}
AnsiString sql;
sql.printf("delete from RESULTS where POS = %d and ord = %d", position, ord);
try
{
Query_SQL->CommandText = sql;
Query_SQL->ExecSQL();
}
catch (Exception &e)
{
}
if (field->write_field_code)
{
field_code.printf("'%s'", field->field_code);
}
else
{
field_code = "NULL";
}
AnsiString field_description;
if (field->write_field_description)
{
field_description.printf("'%s'", field->field_description);
}
else
{
field_description = "NULL";
}
sql.printf("insert into RESULTS (POS, FIELD_CODE, FIELD_DESC, ORD, RVALUE) VALUES (%d, %s, %s, %d, '%08X')", position, field_code, field_description, ord, value);
try
{
Query_Insert->Params->Items[0]->AsInteger = position;
Query_Insert->Params->Items[1]->AsString = field_code;
Query_Insert->Params->Items[2]->AsString = field_description;
Query_Insert->Params->Items[3]->AsInteger = ord;
Query_Insert->Params->Items[4]->AsString = value;
Query_Insert->Params->Items[5]->Clear();
Query_Insert->ExecSQL();
// Query_SQL->CommandText = sql;
// Query_SQL->ExecSQL();
}
catch (Exception &e)
{
return -1;
}
return 0;
从代码的注释部分可以看出,我试图对SQL查询进行参数化,以加快其反复执行但没有重大改变。所有电话都在交易中:
TDBXTransaction *transaction = DataModule->Database->BeginTransaction();
unsigned int i;
unsigned int c = meters.size();
for (i = 0; i < c; i++)
{
...
DataModule->InsertDefaultValues(meters[i]); // <---- here are our INSERTs
...
}
DataModule->Database->CommitFreeAndNil(transaction);
transaction = NULL;
gstat -h命令在数据库文件上的输出如下:
Database "C:\ELMA\EDEX\CAL_RESULTS.FDB"
Database header page information:
Flags 0
Checksum 12345
Generation 33255
Page size 4096
ODS version 11.2
Oldest transaction 33246
Oldest active 33247
Oldest snapshot 33247
Next transaction 33248
Bumped transaction 1
Sequence number 0
Next attachment ID 60
Implementation ID 16
Shadow count 0
Page buffers 0
Next header page 0
Database dialect 1
Creation date Jul 6, 2013 12:58:03
Attributes force write
Variable header data:
*END*
firebird.conf中的DefaultDbCachePages是2048。
在删除和插入记录期间,fbserver.exe进程完全使用一个CPU核心。
答案 0 :(得分:0)
您是否在Windows中激活了“系统还原”?如果是这样,请尝试取消激活它,看看性能是否更好。数据库文件也存在问题,扩展名为.GDB。如果是这种情况,请尝试将数据库文件重命名为.FDB。
答案 1 :(得分:0)
慢速方法的原因不是插入,而是在它们之前调用的删除。这个简单的SQL命令加速了我的方法几次。
CREATE INDEX INDEX_RESULTS ON RESULTS ( POS, ORD );
我还会做另一个优化 - 而不是删除+插入,我将使用初始插入,然后只更新。同样在这种情况下,为用于寻址特定记录的列定义索引非常重要。有时索引可以通过几个订单加速。我做了以下测试:
10000次更新,没有索引 - 300秒
10000次更新,索引为1.6秒