1 TB Firebird 数据库:初步报告
德米特里·库兹缅科,最后更新于2014年3月31日
阅读我们关于更大(1.7太字节)数据库的文章:关于1.7太字节Firebird SQL数据库的更多详情。
为什么要创建太字节级的Firebird数据库?
许多公司使用大型Firebird数据库,并依赖它们来支持重要的业务运营。一些Firebird数据库已经达到数百吉字节的规模,并且还在持续增长(参见“谁是大户?”部分),很容易预测它们何时会变成2倍、3倍或5倍大。因此,数据库管理员和供应商有兴趣研究Firebird在处理大型数据库时的表现,并获得一些管理建议。
此外,我们在创建1Tb Firebird数据库时考虑的一个重要原因是最终消除普遍认为Firebird是“小型数据库”数据库引擎的看法。这个神话现在似乎已经破灭,但一些分析师和记者经常将其从坟墓中挖出,我们希望最终结束这种荒谬的看法。
| ## 硬件 |
Firebird以其惊人的可扩展性而闻名,这项调查再次证实了这一点。这个实验的初始目的仅仅是创建一个1Tb大小的Firebird数据库,因此我们使用了普通的台式计算机:
表1:硬件
| 组件 | 参数 |
| CPU | AMDAthlon 64 x2 5200 |
| 内存 | 4GB |
| 主板 | MSI K9N Platinum |
| 硬盘1(操作系统和临时文件) | ST3160815AS,160GB,SATA II |
| 硬盘2(辅助) | HDT721064SLA360,640GB,SATA II |
| 硬盘2(辅助) | HDS728080PLA380,80GB,SATA I |
| 硬盘3(数据库) | ST31500341AS,1.5TB,SATA II(固件CC1H) |
本质上,我们将1.5Tb硬盘放入办公室的一台台式机中,没有进行任何其他修改。该硬盘格式化的簇大小为16Kb(与数据库页面大小相同,如下所示)。
软件
由于这是一台台式计算机,操作系统为Windows XP Professional SP3,32位。为了实际执行测试,我们使用了基于TPC的工具包中的加载器(可从http://ibdeveloper.com/tests/tpc-c/下载,二进制文件和源代码均可用)。
我们想强调,加载器插入数据的方式与真实场景中的插入方式相同:记录被插入并分布在数据库内部(以及物理磁盘区域)的多个主-从-子从表中,而不是逐表插入。
表2:软件
| 软件 | 版本 |
| 操作系统 | Windows XP Professional SP3,32位 |
| Firebird | 2.1.3 SuperServer(快照) |
| 加载器 | 基于tpc测试的自定义加载器 |
计划
我们对这个实验有一个非常直接的计划:
- 创建数据库并加载1Tb数据,不带索引
- 创建主键和适当的索引(因此实际数据库大小超过1Tb)
- 收集数据库统计信息
- 运行几个SQL查询并评估数据库性能
数据库和Firebird服务器配置
数据库页面大小为16384字节,与硬盘簇大小相同,以最大化磁盘吞吐性能(在一次I/O周期内读/写1页)。
在Firebird配置中,我们配置了额外的临时空间目录,并将其指向640Gb的磁盘(其中约300Gb可用)。
加载步骤
数据通过几个步骤加载到该数据库中。在加载操作期间,计算机被用作普通台式机(我们运行了MS Office、Firefox、IBAnalyst等–大约8-12个程序同时运行)。如果我们只为此任务专用硬件,可能会更快,因此请将这些值仅视为低端示例;它们绝对不是最佳结果。
表3:加载操作
| |
| 描述 | 值 |
| 加载时间 | 约70小时 |
| 插入的总记录数 | 62亿 |
| 平均插入速度 | 24500条记录/秒 |
| 平均记录大小 | 146字节(最小13字节,最大600字节) |
| 事务数 | 646489 |
我们花了约4天时间加载,之后我们得到了一个正好1Tb大小的Firebird数据库(即1 099 900 125 184字节)。
下面您可以在FBDataGuard查看器中看到数据库增长和事务动态:

索引
我们逐个创建索引,并记录了它们的创建时间和用于排序的临时文件的大小。
最大的索引是为表ORDER_LINE创建的。其主键包含四个字段(Smallint、Smallint、Integer和Smallint)。此排序索引的临时文件为182Gb,数据库中最终索引大小为29.3Gb。
有趣的是,即使对于拥有38亿条记录的表,索引深度也为3,因为页面大小为16384字节,因此使用主键搜索该表的数据时没有额外开销。
统计信息
之后,我们收集了数据库统计信息。耗时7小时32分45秒。
我们将关键统计信息放入一个表中,并包含了一些查询和时间测量:
表4:1Tb数据库的综合统计信息
| 表名 | 记录数 | 大小,Gb | select count(*)的执行时间 | 索引创建时间 | 临时文件大小,Gb | 索引大小,Gb |
| WAREHOUSE | 1240 | 0.002 | 0s | 0 | 0 | 0.0 | | ITEM | 100000 | 0.012 | 0.7s | - | - | 0.0 | | DISTRICT | 124000 | 0.017 | 0.7s | 6 | - | 0.0 | | NEW_ORDER | 111600000 | 32 | 20m 00s | 23m 00s | 4.56 | 0.8 | | CUSTOMER | 372000000 | 224 | - | 41m 00s | - | 2.6 | | customer_last | | | | 1h 52m 32s | 12.4 | 2.3 | | fk_cust_ware | | | | 2h 10m 51s | - | 2.3 | | HISTORY | 372000000 | 32 | - | - | - | - | | ORDERS | 372000000 | 25 | 32m 00s | 45m 41s | 15.2 | 2.5 | | STOCK | 1240000000 | 404 | - | 3h 34m 44s | 41.5 | 9.2 | | ORDER_LINE | 3720051796 | 359 | - | 12h 6m 18s | 182.0 | 29.3 |
数据库统计信息可从此处下载。
您可以使用免费的 FBDataGuard Community Edition 查看器来解读文本数据,不仅可以看到数据库性能指标,还能了解 CPU 和内存消耗情况。
查询
首先,我们对几个表执行了 select count(*) 查询(见上表第 4 列)。众所周知,由于 Firebird 的多版本特性,对整个表执行 select count(*) 对服务器来说是一项昂贵的操作,因为它需要访问每一页数据,经验丰富的 Firebird 开发者通常不会使用 select count(*),但我们使用它来展示数据库和硬件的整体性能比率。
执行完 select count 查询后,我们运行了来自真实场景的查询,说实话,我们对如此出色的结果感到惊讶。请自行查看:
| 查询 | 统计信息 | 描述 |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id |
PLAN JOIN (WAREHOUSE NATURAL, CUSTOMER INDEX (FK_CUST_WARE)) ------ 性能信息 —— 准备时间 = 15ms 执行时间 = 79ms 平均获取时间 = 6.08 ms 当前内存 = 272 264 476 最大内存 = 272 514 048 内存缓冲区 = 16 384 从磁盘读取到缓存 = 82 从缓存写入磁盘 = 0 从缓存获取 = 3 648 |
对包含 12400 和 372000000 条记录的表进行简单连接,无 WHERE 条件。“平均获取时间 = 6.08 ms” 指获取第一行的时间。 |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 性能信息 —— 准备时间 = 16ms 执行时间 = 78ms 平均获取时间 = 6.00 ms 当前内存 = 272 266 148 最大内存 = 272 514 048 内存缓冲区 = 16 384 从磁盘读取到缓存 = 88 从缓存写入磁盘 = 0 从缓存获取 = 3 656 |
对相同表进行连接,条件强制选择近期记录。“平均获取时间 = 6.00 ms” 指获取第一行的时间。 |
| select count(*) from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 结果 = 30000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 性能信息 —— 准备时间 = 0ms 执行时间 = 453ms 平均获取时间 = 453.00 ms 当前内存 = 272 263 844 最大内存 = 272 514 048 内存缓冲区 = 16 384 从磁盘读取到缓存 = 1 048 从缓存写入磁盘 = 0 从缓存获取 = 60 024 |
统计上一个查询的记录数 |
| SELECT * FROM ORDER_LINE WHERE OL_W_ID = 500 |
Plan PLAN (ORDER_LINE INDEX (ORDER_LINE_PK)) ------ 性能信息 —— 准备时间 = 0ms 执行时间 = 94ms 平均获取时间 = 7.23 ms 当前内存 = 136 445 536 最大内存 = 136 592 176 内存缓冲区 = 8 192 从磁盘读取到缓存 = 150 从缓存写入磁盘 = 0 从缓存获取 = 2 402 |
对最大表(38 亿条记录)的查询。“平均获取时间 = 7.23 ms” 指获取第一行的时间。 |
<br>Plan<br><br>PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))<br><br> <br><br>------ 性能信息 ------<br><br>准备时间 = 0ms<br><br>执行时间 = 3s 438ms<br><br>平均获取时间 = 0.01 ms<br><br>当前内存 = 136 445 496<br><br>最大内存 = 136 592 176<br><br>内存缓冲区 = 8 192<br><br>从磁盘读取到缓存 = 1 840<br><br>从缓存写入磁盘 = 0<br><br>从缓存获取 = 598 636<br> |
||
| SELECT * FROM ORDER_LINE WHERE OL_W_ID = 500 |
对最大表(38 亿条记录)的相同查询,但这次我们获取了所有记录(共获取 299245 条记录)。 | |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id and (c_w_id > 8000) and (c_w_id < 10000) |
Plan PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 性能信息 —— 准备时间 = 0ms 执行时间 = 125ms 平均获取时间 = 9.62 ms 当前内存 = 272 270 824 最大内存 = 272 514 048 内存缓冲区 = 16 384 从磁盘读取到缓存 = 91 从缓存写入磁盘 = 0 从缓存获取 = 3 659 |
连接包含 1240 条记录和 3.72 亿条记录的表。 |
| select count(*) from WAREHOUSE, customer where c_w_id = w_id and (c_w_id > 8000) and (c_w_id < 10000) 结果 = 59 970 000 |
Plan PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 性能信息 —— 准备时间 = 0ms 执行时间 = 13m 4s 718ms 平均获取时间 = 784 718.00 ms 当前内存 = 272 268 532 最大内存 = 272 514 048 内存缓冲区 = 16 384 从磁盘读取到缓存 = 2 332 583 从缓存写入磁盘 = 0 从缓存获取 = 119 977 902 |
统计上一个查询的记录数 |
总结
在此实验中,Firebird 展示了以下结果:
-
毫无疑问能够处理大型数据库。我们相当确信,在合适的硬件上可以创建和使用 32 Tb 的数据库,Firebird 将展现出与较小数据库(即 1Tb 及以下)相同的高性能。
-
良好的可扩展性和令人惊叹的小内存占用。1Tb 数据库是在普通台式电脑上创建的,更重要的是,它可以用于执行常规查询:如果您不获取数百万条记录,查询速度与中等规模数据库(10-15Gb)相同。
这并非本实验的终点:我们计划运行一些查询,收集更多统计信息,并很快发布更详细的报告。请持续关注。
联系方式
请将所有问题和咨询发送至 [email protected]