23 种加速 Firebird 的更多方法
Alexey Kovyazin, IBSurgeon, [email protected], 2019年1月8日
翻译:葡萄牙语
为什么是“另外23种”?
你们中的一些人可能还记得2016年5月发表的文章《加速 Firebird 的45种方法》。现在是时候发布下一系列技巧和窍门了,这些内容主要基于对具有大量连接(1000+)的 Firebird 数据库和服务器进行优化和维护的经验。
1. 在 Windows Server 2016 和 2019 中将电源选项设置为高性能
默认情况下,Windows Server 的电源计划设置为“平衡”,这不适合数据库服务器。将其设置为“高性能”,对于 CPU 密集型操作可获得约 +20% 的性能提升。可以在线设置,无需重启或重新启动。下图显示了 CPU 图表,展示了“高性能”电源计划的优势:

关于我们对 Windows 电源计划进行测试的更多详细信息可在此处找到。
2. 在 Windows 上为 Classic 架构启用“允许服务与桌面交互”
如果您在 Windows 上使用 Classic 架构的 Firebird,请勾选“允许服务与桌面交互”。如果没有此设置,“桌面堆”资源将受到 Windows 的限制,Firebird 无法打开超过 250-300 个连接(取决于数据库的元数据和相关的内存消耗)——将会出现内存不足错误。

3. 注意:域控制器
问题是,具有域控制器角色的 Windows 会禁用 Active Directory 数据库所在磁盘的写入缓存。
这会以多种方式影响 Firebird(当然也会影响其他应用程序),并且其性能明显低于没有 Active Directory 角色的服务器。
请注意,此问题会影响诸如 Windows Small Business Server 2011 等流行的 Windows 版本,以及其他带有 DC 的版本。
4. 在 Linux 上增加“最大打开文件数”限制
如果您使用 Linux 作为数据库服务器,请不要忘记调整 Firebird 的限制。使用以下命令检查 Firebird 进程(SuperServer 或 SuperClassic)的限制:
cat /proc//limits
并注意最大打开文件数那一行。
Firebird 每个连接最多可使用 4 个句柄,如果您看到类似这样的内容:
Max open files 4096 4096 files
这意味着 Firebird 进程所服务的连接总数将被限制在 1000 左右。
请注意——如果服务器上有 4 个数据库,则每个数据库的连接都会被计入。
设置得更高——我建议 65535。
不要忘记在重启 Firebird 进程后再次检查:是否已应用。
对于 Classic 架构,有必要检查并增加用户“firebird”的限制。
5. 使用现代 Linux
是的,我明白这个建议很平常,但我多次看到从 CentOS 6 迁移到 7、Ubuntu 12 迁移到 16(在相同的硬件上!)后性能得到了良好的提升,所以现在对于具有超过 250-300 个连接的数据库服务器来说,这是必备建议。现代 Linux 是进一步优化步骤的先决条件。
推荐的 Linux 版本:CentOS 7.x 和 Ubuntu 16、18。
6. 在 Windows 上为文件缓存保留 40% 的 RAM
操作系统内存管理器对内存分配有影响,默认情况下,Windows 需要 40% 的 RAM 用于文件缓存。
不幸的是,糟糕的 Windows 任务管理器工具将用于文件缓存的内存显示为“空闲”,一些管理员试图让 Firebird 消耗所有这些空闲内存,因此他们将 firebird.conf 中的 DefaultDBCachePage 参数设置为非常高的值,这通常会导致交换。
在 Windows 上,请始终使用 RAMMap 工具查看实际的内存使用情况。
对于 Windows Server(专用于作为 Firebird 服务器)的经验法则是:Firebird 内存(工作集)应小于总 RAM 的 40%。如果所有进程的工作集总大小超过 50%,Windows 可能会开始交换。
请注意:这里的“保留”不仅意味着“不要在 Firebird 中设置过多的页缓冲区”,而且同样重要的是,限制其他软件的内存使用。例如,如果您的服务器上同时运行 MS Exchange 或 MSSQL 与 Firebird,请确保限制它们的内存需求。
如果您有兴趣了解详细信息,我录制了专门讨论 Firebird 内存管理的网络研讨会:
7. 在 Linux 上为文件缓存保留 30% 的 RAM
Linux 处理文件缓存的方式与 Windows 不同,一般来说,用于文件缓存的 RAM 量可以显著少于 Windows,而不会导致 Firebird 性能明显下降。但是,为了保证具有大量连接的系统的高性能,特别是在 Classic 和 SuperClassic 上,为文件缓存保留 30% 的 RAM 是个好主意。
8. 在 Linux 上使用 irqbalance
irqbalance 通常可以改善具有大量核心的服务器上 Firebird 的性能和 CPU 负载均衡。
9. 对于虚拟机——注意内存过量分配
虚拟机可以配置为拥有比宿主机上物理存在的更多的内存——这被称为内存过量分配(在不同虚拟化系统中名称可能不同)。这意味着在内存消耗高峰时(在数据库服务器 VM 或相邻 VM 上),可能会开始交换,这将导致显著的延迟。对于用于数据库服务器的高性能 VM,所有内存都应该是静态的。
10. 对于虚拟机——检查 VM 限制
通常 VM 创建时带有默认的 CPU 和 IO 限制,这些限制可能非常低,例如 50 IOPS 和 10% CPU。检查您的服务器 VM 设置并移除任何限制——高性能数据库服务器应该拥有所有可能的 CPU、带宽和 IO。
11. 清理 Firebird 临时文件
Firebird 为各种操作创建许多临时文件:排序、BLOB 处理、跟踪。这些文件存储在以下位置:Windows 上为 C:\ProgramData\firebird,Linux 上为 / tmp / firebird
通常这些文件应该被自动清理,但有时不会发生(例如,在服务器重启的情况下)。
定期检查这些文件夹并清理旧文件——可能会有许多 GB 的过期文件 fb_NNN,清理它们将释放系统驱动器上的空间。
12. 使用大 Firebird 缓存时不要忘记启用文件缓存
如您所知,Firebird 缓存(也称为“页缓冲区”)由 firebird.conf/databases.conf 中的 DefaultDBCachePages 参数指定,或直接在数据库头部中指定。
在 Firebird 3 SuperServer 中,此缓存的大小可以设置得很高,但重要的是要记住另一个参数:FileSystemCacheThreshold。
如果 FileSystemCacheThreshold 小于 DefaultDBCachePages 或页缓冲区,则操作系统的文件缓存将不会被使用,这可能导致性能问题。
在 99% 的情况下,最好启用文件缓存。
为确保这一点,请始终按照以下规则设置参数:
- DefaultDBCachePages = X
- FileSystemCacheThreshold = X+ N, N>1
在极少数情况下,禁用文件缓存可以提高性能——如果您有这样的例子,请联系我——[email protected]!
13. 加速安全数据库
每次连接到 Firebird 数据库都会建立到安全数据库(在 Firebird 3 中为 security3.fdb)的连接,并执行多次读取和写入(事务页面、头部页面)。如果您有频繁的连接,安全数据库的性能可能会成为问题。
至少,你可以执行以下操作:
- 增加 securityN.fdb 的页面缓冲区(经验最优值为 256 个缓冲区)
- 将 security3.fdb 移动到快速驱动器上(这是 Firebird 3 的标准特性,在 2.5 中需要重新安装)
然后,你可以为安全数据库设置 Forced Writes OFF——在这种情况下,损坏的小概率不是问题。
最激进的方法是将安全数据库设为只读——这将消除对它的所有写入。
如果你不经常更改安全数据库中的用户,这是最佳解决方案。
14. 在 Firebird 3 上尝试 SuperClassic
在 Firebird 3 中,SuperServer 架构被大力宣传为终极性能解决方案,但有些负载类型在 SuperClassic 下表现出更好的性能(但不是 Classic——它总是比 SuperServer/SuperClassic 运行得慢)。
如何以安全的方式开展这个实验?请按照以下步骤操作:
尝试 SuperClassic
- 在 firebird.conf 中设置
- ServerMode=SuperClassic
- DefaultDbCachePages=1024
- gfix -buff 0
- 重启 Firebird
恢复为 SuperServer
- 在 firebird.conf 中设置
- ServerMode=SuperServer
- DefaultDbCachePages=N # N*页面大小*数据库数量 < 25% RAM
- FileSystemCacheThreshold = N+1
- gfix -buff 0
- 重启 Firebird
请将实验结果写信告诉我([email protected]),我很想看到结果。
15. 大数据库?增加页面大小
默认情况下,Firebird 数据库具有以下页面大小:
- 2.5 - 4096 字节
- 3.0 - 8192 字节
然而,最大页面大小为 16K(在 4.0 中为 32K)。
对于超过 100Gb 的数据库,95% 的情况下,最好使用可用的最大页面大小,以便:
- 减小索引深度。建议索引深度小于或等于 3。深度为 4 和 5 的索引会慢得多
- 提高 RAM 的利用率。Firebird 缓存以页面为单位指定,页面大小为 8K 的 1000 个页面将是 8Mb 的实际内存,而 16K 则为 16Mb。
- 减少系统页面数量。它将加快对大表记录的访问(减少指针-指针-数据页的跳转),并有助于大型 SQL 查询的准备。要增加数据库的页面大小,应使用 gbak 工具备份数据库,然后使用参数 -page 恢复( gbak -c -page 16384)。
请注意:如果你的数据库有许多小 blob,增加页面大小可能会减少碎片或增加碎片,很难预测它会提高还是降低性能。
16. 不要使用 no_reserve 标志
no_reserve 标志使 Firebird 不在数据页上为 UPDATE 或 DELETE 后可能出现的记录版本保留空闲空间(30%)。此标志允许以更紧凑的方式存储数据(数据库大小也更小),但在 UPDATE/DELETE 的情况下,所有更改都会转到新的数据页。因此,在带有 no_reserve 标志的数据库中,UPDATE/DELETE 操作较慢。
因此,如果你的数据库不是只读的,我建议移除 no_reserve 标志。
如何检查是否设置了它——请查看以下命令输出中的 Attributes 行
gstat -h database
如何禁用:
gfix -use reserve database
执行此命令后,新的数据页将带有保留空间创建。
然而,要达到完整效果,有必要使用 gbak 备份数据库然后恢复,在这种情况下,所有数据页都将带有保留空间。
请注意:移除 no_reserve 标志并备份/恢复后,数据库大小将会增长。
17. 为 Firebird 锁表设置较高的初始大小
锁表是 Firebird 的机制,用于同步对内部引擎对象的访问。
Firebird 锁表可以自动增长,但其增长是缓慢的操作,可能导致微冻结。锁表只能从初始大小开始增长(在 firebird.conf 中设置)。
为防止锁表多轮增长,一个好主意是在工作周期(天、周等)结束时观察锁表的大小,然后将其设置为 firebird.conf 中的初始大小。
LockMemSize=99999999
供你参考:在约 1000 个用户的高负载系统上,LockMemSize 通常低于 200Mb。
18. 使用 fb_lock_print 统计数据库连接数
获取数据库连接数是数据库开发人员的常见任务:例如,可能出于许可目的需要它。
开发人员通常使用查询 SELECT count(*) FROM MON$ATTACHMENTS 来获取此值,但这不是最佳方式:频繁查询 MON$ 表会给数据库带来负担,因此最好使用替代方法:
运行
fb_lock_print -d database_name | alias
并检查 Owners 值——它将显示当前到数据库的连接数。
19. 避免不必要的 LEFT JOIN
我经常看到像这样的查询:
T1 LEFT JOIN T2 ON (…) WHERE T2.Field_condition
本质上,对 T2 的条件排除了 LEFT JOIN T2 输出中的 NULL,因此可以将 LEFT JOIN 改为 INNER JOIN——它不会影响查询结果。
INNER JOIN 为 Firebird 优化器提供了更多自由,在现代版本的 Firebird 中,它的优化比 LEFT 好得多。
尤其在以下情况下有意义:
- WHERE 子句中没有针对 T1 的条件
- T2 是一个小表
20. 避免不必要的记录计数
复杂数据库查询和存储过程中的另一个常见错误是使用 select count() 仅仅为了检查记录是否存在。
以下查询将根据 condition1 读取所有记录:
(select count(*)…. where condition11) >0
最好改用这种构造
Exists(select first 1 id where condition1)
如果 condition1 返回多于 1 条记录,所提出的选项将快得多,因为它不读取所有记录,在获取第一条记录后就停止。
21. 避免存储过程中不必要的排序
存储过程内查询结果的排序应由业务逻辑证明其合理性。
例如,在下面的存储过程示例中,从业务逻辑的角度来看,ORDER BY 子句是无用的,但它增加了不必要的排序操作。
create or alter procedure NEW_PROCEDURE
returns (
SUMX double precision)
as
declare variable _amount double precision;
begin
for select T1.amount from Table1 t1 where ....
order by id
into :_amount
do
begin
sumx=sumx+_amount
end;
suspend;
end
检查你的 PSQL 代码中是否有类似情况,并移除无用的 ORDER BY(以及 distinct 和 UNION)。
22. 不要在没有必要的情况下保持查询处于准备状态
我们经常看到每个连接中有 500-1000 个已准备的语句(可以通过 MON$ 查询检查)。
其中绝大多数只运行一次,然后它们就闲置在 RAM 中,使 Firebird 工作集变大,并减慢 MON$ 查询。
建议仅当 SQL 查询打算多次启动,或者其准备时间很长时(对于具有大量连接和访问巨大表的非常大的查询可能如此),才将其保持在准备状态。
23. 始终关闭具有大型排序的查询
在带有排序(ORDER BY、GROUP BY、UNION、distinct)的 SQL 查询关闭之前,Firebird 会将排序后的记录保留在内存中。为排序分配的内存大小由 firebird.conf 中的 TempCacheLimit 参数设置,默认值为 64Mb。
即使增加了 TempCacheLimit,具有大量排序记录的长运行查询最终也会消耗所有分配的量,结果排序将转到临时文件(即磁盘)。因此,它可能导致显著的缓慢。
建议及时关闭所有此类查询。
有问题?
请随时通过 [email protected] 与我联系,提出任何问题!