此页面为机器翻译。请阅读英文原文。 English

IBSurgeon 文库

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)的限制:

Code
cat /proc//limits

并注意最大打开文件数那一行。

Firebird 每个连接最多可使用 4 个句柄,如果您看到类似这样的内容:

Code
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

  1. 在 firebird.conf 中设置
  2. ServerMode=SuperClassic
  3. DefaultDbCachePages=1024
  4. gfix -buff 0
  5. 重启 Firebird

恢复为 SuperServer

  1. 在 firebird.conf 中设置
  2. ServerMode=SuperServer
  3. DefaultDbCachePages=N # N*页面大小*数据库数量 < 25% RAM
  4. FileSystemCacheThreshold = N+1
  5. gfix -buff 0
  6. 重启 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 行

Code
gstat -h database

如何禁用:

Code
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 读取所有记录:

Code
(select count(*)…. where condition11) >0

最好改用这种构造

Code
Exists(select first 1 id where condition1)

如果 condition1 返回多于 1 条记录,所提出的选项将快得多,因为它不读取所有记录,在获取第一条记录后就停止。

21. 避免存储过程中不必要的排序

存储过程内查询结果的排序应由业务逻辑证明其合理性。

例如,在下面的存储过程示例中,从业务逻辑的角度来看,ORDER BY 子句是无用的,但它增加了不必要的排序操作。

Code
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] 与我联系,提出任何问题!