18.4. 资源消耗

18.4.1. 内存

shared_buffers (integer)

设置数据库服务器将使用的共享内存缓冲区数量。缺省通常是128兆字节(128MB), 但是如果你的内核设置不支持这么大,那么可以少些(在initdb的时候决定)。 每个缓冲区大小的典型值是128千字节,(BLCKSZ的非缺省值改变最小值) 不过,这个数值比最小值大一些通常需要更好的性能。 这个选项只能在服务器启动的时候设置。

如果你有1GB或更多内存的专用数据库服务器, 对于shared_buffers合理的初始值是您的系统内存的25%。 有一些工作负载,甚至在那里对于shared_buffers大设置是有效的, 但因为PostgreSQL也依赖于操作系统缓存, 它是不可能的,RAM到shared_buffers的多于40%的分配比更少数量的工作的更好。 对于shared_buffers的大量设置 通常要求相应增加checkpoint_segments, 为了延长写大量新的或者需较长时间修改的数据的进程。

对于少于1GB RAM系统, 较小百分比内存是相应的, 以便为操作系统留有足够的空间。 此外,在Windows上,shared_buffers大点的值不是很有效。 您可能会发现更好的结果保持设置相对较低,并且使用操作系统的缓存代替。 在Windows系统上shared_buffers的有用范围一般是从64MB到512MB。

temp_buffers (integer)

设置每个数据库会话使用的临时缓冲区的最大数目。这些都是会话的本地缓冲区, 只用于访问临时表。缺省是8兆字节(8MB)。这个设置可以在独立的会话内部设置, 但是只有在会话第一次使用临时表的时候才能增长; 企图在该会话里随后改变该数值是无效的。

一个会话将按照temp_buffers给出的限制,根据需要分配临时缓冲区。 如果在一个并不需要大量临时缓冲区的会话里设置一个大的数值, 其开销只是一个缓冲区描述符,或者说每个temp_buffers增加大概64字节。不过, 如果一个缓冲区实际上被使用,那么就会额外消耗8192字节(或者说是BLCKSZ字节)。

max_prepared_transactions (integer)

设置可以同时处于"预备"状态的事务的最大数目(参阅PREPARE TRANSACTION)。 把这个参数设置为零(这是缺省值)则关闭预备事务的特性。 这个值只能在服务器启动的时候设置。

如果你不打算使用预备事务,这个参数也可以设置为零。 避免预备事务的偶然建立。如果你使用它们, 你可能会需要把max_prepared_transactions设置成至少和max_connections 一样大,以避免每个会话可以有预备事务挂起。

当运行备库服务器时,你必须设置相同参数或者比主服务器上更高参数值。 否则,在备库服务器上不允许查询。

work_mem (integer)

声明内部排序操作和Hash表在开始使用临时磁盘文件之前使用的内存数目。 缺省数值是1兆字节(1MB)。请注意对于复杂的查询, 可能会同时并发运行好几个排序或者散列操作;每个都会被批准使用这个参数声明的这么多内存, 然后才会开始求助于临时文件。同样,好几个正在运行的会话可能会同时进行排序操作。 因此使用的总内存可能是work_mem的好几倍。 当选择这个值的时候,必须记住这个事实。 ORDER BY, DISTINCT和融合连接都要用到排序操作。 Hash表在散列连接、散列为基础的聚合、散列为基础的IN子查询处理中都要用到。

maintenance_work_mem (integer)

声明在维护性操作(比如VACUUM, CREATE INDEXALTER TABLE ADD FOREIGN KEY)中使用的最大的内存数。 缺省是16兆字节(16MB)。因为在一个数据库会话里, 任意时刻只有一个这样的操作可以执行,并且一个数据库安装通常不会有太多这样的工作并发执行, 把这个数值设置得比work_mem更大是安全的。 更大的设置可以改进清理和恢复数据库转储的速度。

请注意,当运行自动清理, 直至autovacuum_max_workers次分配这个内存, 所以要小心,不要设置默认值太高。

max_stack_depth (integer)

声明服务器的执行堆栈的最大安全深度。 为此设置一个参数的原因是内核强制的实际堆栈尺寸(就是ulimit -s或者局部等效物的设置) 小于安全的一兆字节左右的范围。需要这个安全界限是因为在服务器里,并非所有过程都检查了堆栈深度, 只是在可能递规的过程,比如表达式计算这样的过程里面才进行检查。缺省设置是2兆字节2MB, 这个值相对比较小,不容易导致崩溃。但是,这个值可能太小了,以至于无法执行复杂的函数。

max_stack_depth参数设置得大于实际的内核限制意味着 一个正在运行的递归函数可能会导致一个独立的服务器进程的崩溃。 在PostgreSQL能够检测内核限制的平台上, 服务器将不允许你将其设置为一个不安全的值。 因为并非所有平台都能够检测,所以还是建议你在此设置一个明确的值。

18.4.2. 磁盘

temp_file_limit (integer)

指定会话可以使用临时文件的最大磁盘空间,如排序和哈希临时文件, 或持有游标的存储文件。一个事务试图超过这个限制将被取消。 该值是指定的千字节,并且-1(缺省)意味着没有限制。 只有超级用户可以更改此设置。

此设置限制任何时刻通过临时文件使用给定PostgreSQL会话使用的总空间。 应当指出的是,使用显式临时表的磁盘空间, 而不是使用查询执行的幕后临时文件, 并强调影响这个限制。

18.4.3. 内核资源使用

max_files_per_process (integer)

设置每个服务器进程允许同时打开的最大文件数目。缺省是1000。 如果内核强制一个合理的每进程限制,那么你不用操心这个设置。 但是在一些平台上(特别是大多数BSD系统), 内核允许独立进程打开比个系统真正可以支持的数目大得多得文件数。 如果你发现有"Too many open files"这样的失败现像,那么就尝试缩小这个设置。 这个值只能在服务器启动的时候设置。

shared_preload_libraries (string)

这个变量声明一个或者多个在服务器启动的时候预先装载的共享库。 比如'$libdir/mylib'会在加载标准库目录中的库文件之前预先加载' mylib.so(在某些平台上可能是mylib.sl)库文件。 所有库名转换成小写,除非双引号引用。如果有多个库被加载,将他们的名字用逗号分隔。 这个值只能在服务器启动的时候设置。

可以用这个方法预先装载PostgreSQL的过程语言库, 通常是使用'$libdir/plXXX'语法, 这里的XXXpgsql, perl, tcl或者python之一。

通过预先装载一个共享库(以及在需要的时候初始化它), 我们就可以避免第一次使用这个库的加载时间。不过, 启动每个服务器进程的时间可能会增加, 即使进程从来没有使用过这些库也这样。 因此我们只是建议对那些将被大多数会话使用的库才使用这个选项。

注意: 在Windows主机上,在服务器启动时预加载库并不会减少所需的时间来启动每个新的服务器进程; 每个服务器进程将重新加载所有的预置库。 然而,shared_preload_libraries仍然是在Windows主机上有用的, 因为某些共享库可能需要执行只发生在启动时的某些操作 (例如,一个共享库可能需要预定轻量级锁或共享内存,启动开始之后你不能这样做)

如果没有找到声明的库,那么服务器启动将失败。

每一个支持PostgreSQL的库都有一个"magic block"用于保证兼容性。 因此,不支持PostgreSQL的库不能用这种办法加载。

18.4.4. 基于开销的清理延迟

VACUUMANALYZE命令执行过程中, 系统维护一个内部的记数器,跟踪所执行的各种I/O操作的近似开销。 如果积累的开销达到了vacuum_cost_limit声明的限制, 那么执行这个操作的进程将睡眠vacuum_cost_delay指定的时间。 然后它会重置记数器然后继续执行。

这个特性的目的是允许管理员减少这些命令在并发活动的数据库上的I/O影响。 比如,像VACUUMANALYZE这样的维护命令并不需要迅速完成, 并且不希望它们严重干扰系统执行其它的数据库操作。 基于开销的清理延迟为管理员提供了一个实现这个目的的手段。

这个特性缺省手动发出VACUUM命令是关闭的。 要想打开它,把vacuum_cost_delay变量设置为一个非零值。

vacuum_cost_delay (integer)

以毫秒计的时间长度,如果超过了开销限制,那么进程将睡眠一会儿。 缺省值0关闭基于开销的清理延迟特性。正数值打开基于开销的清理。 不过,要注意在许多系统上,睡眠的有效分辨率是10毫秒; 把vacuum_cost_delay设置为一个不是10的整数倍的数值与 将它设置为下一个10的整数倍作用相同。

当使用基于成本的清理,vacuum_cost_delay的适当值通常是相当小的, 也许10或20毫秒。调节清理的资源消耗最好是通过改变其它清理开销参数完成的。

vacuum_cost_page_hit (integer)

清理一个在共享缓存里找到的缓冲区的预计开销。 它代表锁住缓冲池、查找共享的Hash表、扫描页面内容的开销。 缺省值是1。

vacuum_cost_page_miss (integer)

清理一个要从磁盘上读取的缓冲区的预计开销。 它代表锁住缓冲池、查找共享Hash表、从磁盘读取需要的数据块、 扫描它的内容的开销。缺省值是10。

vacuum_cost_page_dirty (integer)

清理修改一个原先是干净的块的预计开销。 它代表把一个脏的磁盘块再次刷新到磁盘上的额外开销。 缺省值是20。

vacuum_cost_limit (integer)

导致清理进程休眠的积累开销。缺省是200。

注意: 有些操作会持有关键的锁,并且应该尽快结束。 在这样的操作过程中,基于开销的清理延迟不会发生作用。 因此开销积累远远高于指定的限制是可能的。 为了避免在这种情况下的长延时, 实际的延迟是vacuum_cost_delay * accumulated_balance / vacuum_cost_limitvacuum_cost_delay * 4 两者之间的最大值。

18.4.5. 后端写进程

从 PostgreSQL 8.0 开始,就有一个独立的服务器进程,叫做后端写进程, 它唯一的功能就是发出写"脏"共享缓冲区的命令。 这么做的目的是让持有用户查询的服务器进程应该很少或者几乎不等待写动作的发生, 因为后端写进程会做这件事情。这样的安排同样也减少了检查点造成的性能下降。 后端写进程将持续的把脏页面刷新到磁盘上,所以在检查点到来的时候,只有几个页面需要刷新到磁盘上。 但是这样还是增加了 I/O 的总净负荷,因为以前的检查点间隔里,一个重复弄脏的页面可能只会冲刷一次, 而同一个间隔里,后端写进程可能会写好几次。在大多数情况下,连续的低负荷要比周期性的尖峰负荷好, 但是在本节讨论的参数可以用于按实际需要调节其行为。

bgwriter_delay (integer)

声明后端写进程活跃轮回之间的延迟。在每个轮回里, 写进程都会为一些脏的缓冲区发出写操作(可以用下面的参数控制)。 然后它就休眠bgwriter_delay毫秒,然后重复动作。 当在缓冲池中没有脏缓冲区时,但是,它会无论bgwriter_delay的值,进入一个较长的睡眠。 缺省值是200(200ms)。 请注意在许多系统上,休眠延时的有效分辨率是10毫秒; 因此,把bgwriter_delay设置为一个不是10的倍数的数值与 设置为下一个10的倍数是一样的效果。 这个选项只能在服务器启动的时候或者在postgresql.conf文件里设置。

bgwriter_lru_maxpages (integer)

在每个轮回里, 不超过这么多个缓冲区将通过后端写进程写入磁盘。 设置为零启动后端写进程。(请注意检查点,通过单独的,专用辅助进程来管理,不受影响。) 缺省值是100。这个选项只能在服务器命令行或者在postgresql.conf文件里设置。

bgwriter_lru_multiplier (floating point)

写在每一轮的脏缓冲区数目是根据通过最近几轮服务器处理所需的新的缓冲区数。 最近平均需求乘以bgwriter_lru_multiplier到达将在下一轮中需要的缓冲区的数目的估计。 脏缓冲区写入直到有许多干净的,可重复使用的缓冲区可用。 (但是,每回写入不超过bgwriter_lru_maxpages的缓冲区。) 因此,1.0的设置表示写入确切预测需要的缓冲区数量的"合适"策略。 较大的值提供针对需求高峰一定的缓冲作用, 而较小的值故意留下服务器进程完成写入。 默认值是2.0。 这个参数只能在postgresql.conf文件或者服务器命令行中设置。

小的bgwriter_lru_maxpagesbgwriter_lru_multiplier减少后端写进程导致的额外I/O负荷, 但是会有可能使服务器进程不得不自己发出写动作,降低查询的交互性。

18.4.6. Asynchronous Behavior

effective_io_concurrency (integer)

设置PostgreSQL预计可以同时执行的并发磁盘的I/O操作数。 增大该数值将增加任何单独的PostgreSQL会话尝试并行启动的I/O操作数。 允许的范围是1到1000,或者零禁用发出异步I/O请求。目前,此设置只影响堆位图扫描。

这个设置很好的起点是包括一个RAID 0或用于数据库的RAID 1镜像的单独驱动器数。 (对于RAID 5奇偶校验驱动器不应该计算在内。) 然而,如果数据库经常忙于在并发会话中发出多个查询, 更低的数值可能是足够的,以保持磁盘阵列繁忙。 比需要保持磁盘繁忙更大的值将只会造成额外的CPU开销。

对于更奇特的系统,如基于内存的存储或由总线带宽限制的RAID阵列 ,正确的值可能是可用I/O路径数。一些试验可能需要找到最好的值。

异步I/O依赖于有效的posix_fadvise功能, 其中一些是操作系统所缺乏的。如果函数不存在,那么这个参数设置为任何东西, 但是零将导致错误。在某些操作系统上(例如Solaris),函数存在,但实际上并没有做任何事情。