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

IBSurgeon 文库

23种加速Firebird的更多方法

Alexey Kovyazin, IBSurgeon, [email protected], 2019年1月8日

翻译:葡萄牙语

为什么是“另外23个”?

你们中的一些人还记得2016年5月发布的文章《45种加速Firebird的方法》。现在是时候发布下一系列技巧和窍门了,这些主要基于对高连接数(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参数设置为非常高的值,这通常会导致交换。

始终使用RAMMap工具来查看Windows上的实际内存使用情况。

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缓存以页面为单位指定,1000页8K页面大小将是8Mb实际内存,而16K将是16Mb。
  • 减少系统页面数量。这将加快对大表记录的访问(减少指针-指针-数据页的跳转),并有助于大型SQL查询的准备。要增加数据库的页面大小,应使用gbak工具备份数据库,然后使用参数-page恢复(gbak -c -page 16384)。

请注意:如果您的数据库包含许多小型blob,增加页面大小可能会减少碎片或增加碎片,并且很难预测性能会提高还是降低。

16. 不要使用no_reserve标志

标志no_reserve使Firebird不在数据页上保留可用空间(30%),这些空间用于UPDATE或DELETE后可能发生的记录版本。此标志允许以更紧凑的方式存储数据(数据库大小也更小),但在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 数据库名称 | 别名

并检查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]