您将如何检查您的Postgresql数据库实例是否需要更多RAM内存来处理其当前的工作数据?
您将如何检查您的Postgresql数据库实例是否需要更多RAM内存来处理其当前的工作数据?
Answers:
如果全部都在Linux上,则总物理RAM应大于磁盘上的数据库大小,以最大程度地减少I / O。最终,整个数据库将位于操作系统读取缓存中,而I / O将仅限于将更改提交到磁盘。我更喜欢通过运行“ du -shc $ PGDATA / base”来找到数据库大小,该方法将所有数据库聚合为一个数字。只要您大于此范围,就可以了。
此外,您可以查看堆和索引块访存的高速缓存命中率。这些度量了PostgreSQL共享缓冲区的命中率。这些数字可能会引起误解-即使共享缓冲区高速缓存中可能遗漏了一些数据,但在操作系统读取高速缓存中仍然有一定的损失。尽管如此,共享缓冲区中的命中仍然比OS读缓存中的命中便宜(后者又比必须返回磁盘便宜了几个数量级)。
为了查看共享缓冲区的命中率,我使用以下查询:
SELECT relname, heap_blks_read, heap_blks_hit,
round(heap_blks_hit::numeric/(heap_blks_hit + heap_blks_read),3)
FROM pg_statio_user_tables
WHERE heap_blks_read > 0
ORDER BY 4
LIMIT 25;
这为您提供了前25名最严重的违规者,其中必须从“磁盘”中获取至少一个块的所有表(同样,可能是OS读取缓存或实际的磁盘I / O)都缺少缓冲区缓存。您可以增加WHERE子句中的值,也可以为heap_blks_hit添加另一个条件以过滤掉很少使用的表。
通过将字符串“ heap”全局替换为“ idx”,可以使用相同的基本查询来检查每个表的总索引命中率。查看pg_statio_user_indexes以获得每个索引的细分。
关于共享缓冲区的快速说明:在Linux中,一个很好的经验法则是将配置参数shared_buffers设置为RAM的1/4,但不超过8GB。这不是一成不变的规则,而是调整服务器的良好起点。如果您的数据库只有4GB,而您有一台32GB的服务器,则8GB的共享缓冲区实际上是过大的,您应该能够将其设置为5或6GB,并且仍有未来增长的空间。
我使用此SQL来显示表与磁盘的命中率:
-- perform a "select pg_stat_reset();" when you want to reset counter statistics
with
all_tables as
(
SELECT *
FROM (
SELECT 'all'::text as table_name,
sum( (coalesce(heap_blks_read,0) + coalesce(idx_blks_read,0) + coalesce(toast_blks_read,0) + coalesce(tidx_blks_read,0)) ) as from_disk,
sum( (coalesce(heap_blks_hit,0) + coalesce(idx_blks_hit,0) + coalesce(toast_blks_hit,0) + coalesce(tidx_blks_hit,0)) ) as from_cache
FROM pg_statio_all_tables --> change to pg_statio_USER_tables if you want to check only user tables (excluding postgres's own tables)
) a
WHERE (from_disk + from_cache) > 0 -- discard tables without hits
),
tables as
(
SELECT *
FROM (
SELECT relname as table_name,
( (coalesce(heap_blks_read,0) + coalesce(idx_blks_read,0) + coalesce(toast_blks_read,0) + coalesce(tidx_blks_read,0)) ) as from_disk,
( (coalesce(heap_blks_hit,0) + coalesce(idx_blks_hit,0) + coalesce(toast_blks_hit,0) + coalesce(tidx_blks_hit,0)) ) as from_cache
FROM pg_statio_all_tables --> change to pg_statio_USER_tables if you want to check only user tables (excluding postgres's own tables)
) a
WHERE (from_disk + from_cache) > 0 -- discard tables without hits
)
SELECT table_name as "table name",
from_disk as "disk hits",
round((from_disk::numeric / (from_disk + from_cache)::numeric)*100.0,2) as "% disk hits",
round((from_cache::numeric / (from_disk + from_cache)::numeric)*100.0,2) as "% cache hits",
(from_disk + from_cache) as "total hits"
FROM (SELECT * FROM all_tables UNION ALL SELECT * FROM tables) a
ORDER BY (case when table_name = 'all' then 0 else 1 end), from_disk desc