我从这个博客中读到,您数据库中只有 20% 的数据获得了 80% 的大量读取。这意味着经常访问数据库中的一小部分数据。因此,您希望确保在缓存(主内存)而不是磁盘中访问 20%。最终,您希望缓存命中率达到 99%。博客提供了这个命令来查找缓存命中率:
SELECT
sum(heap_blks_read) as heap_read,
sum(heap_blks_hit) as heap_hit,
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio
FROM
pg_statio_user_tables;
Run Code Online (Sandbox Code Playgroud)
好的,所以我期待接近 99% 的数字,但现在这是我得到的数字:
# pg_statio_user_tables;
heap_read | heap_hit | ratio
---------------+---------------+------------------------
2214811975866 | 1791164728361 | 0.44712310145763220493
(1 row)
Run Code Online (Sandbox Code Playgroud)
0.44?这甚至不接近 99%。这一定意味着大多数命中都发生在磁盘上,而缓存几乎不存在。什么可能导致这个问题?
jja*_*nes 10
给出的公式仅告诉您PostgreSQL
缓冲区缓存 ( shared_buffers
)内的命中率是多少。
但也许所有未命中都是从操作系统的文件缓存中提取的,而不是实际上从磁盘中提取的。PostgreSQL 没有提供直接的方式让您知道这一点,因为它尽可能地远离内核业务。(其他一些 DBMS 绕过操作系统的文件缓存,但PostgreSQL
没有,它在它之上运行。)
如果您在打开 track_io_timing 的情况下运行,则在最近版本上感受它的一种方法是查看
select sum(blks_read)/sum(blk_read_time) from pg_stat_database
Run Code Online (Sandbox Code Playgroud)
例如,我每毫秒读取时间读取 110 个块。由于我的磁盘并没有那么快,我知道几乎所有这些都是从操作系统文件缓存中读取的,而不是实际上从磁盘中读取的。
如果您将 shared_buffers 设置为系统 RAM 的一小部分(通常建议用于大型系统),那么您可以通过将 shared_buffers 增加为 RAM 的大部分来获得更好看的命中率。请注意,这不太可能为您提供更好的性能,它只会使一些任意数字看起来很漂亮。
无论如何,命中率是“基于神话的管理”的一部分。也许我 20% 的数据负责我 80% 的读取。也许 20% 的博主数据负责他 80% 的阅读。我和博主都不知道这是否适用于您的数据库。也许是,也许不是。
即使是这样,如果我的 20% 的数据仍然远大于我的可用 RAM 怎么办?再多的修修补补也无法让它适合缓存。我将不得不购买更多 RAM,这既昂贵又涉及停机时间,所有这些都是为了解决一个实际上不是问题的“问题”。
如果您有性能问题,您应该调查问题是什么。如果您没有性能问题,那么您最好花时间练习灾难恢复,或者获取测试系统并为其制作真实的负载生成器(以便您可以使用来自测试系统的数据,而不是基于神话)。此外,如果您运行的版本早于 9.2,您应该花时间升级到至少该版本,如果不是更新的话。一旦问题发生,可用于诊断问题的工具一直在变得越来越好,但如果您运行的是旧版本,则无法使用它们。
-- 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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13418 次 |
最近记录: |