慢查询问题
询问慢查询问题的指南
在任何给定的周中,#postgresql IRC 上约 50% 的问题以及 pgsql-performance 上 75% 的问题都要求帮助解决慢查询问题。 但是,请求者很少会提供有关其慢查询的完整信息,这让他们自己以及试图帮助他们的人感到沮丧。
请将与性能相关的问题发布到 pgsql-performance 邮件列表或 IRC 频道。
注意:如果在 IRC 上寻求帮助,请将相关信息发布到像 https://paste.depesz.com/ 这样的粘贴网站上,而不是直接发布到 IRC 上。
另请参阅:报告问题的指南
在发布之前尝试的事项
如果你在发布问题之前尝试以下事项,可以节省很多时间。
- 如果你还没有阅读过,请阅读 使用 EXPLAIN。
- ANALYZE 相关表以确保统计数据是最新的;
- 收集有关表大小(ntuples、npages)和列值(nullfrac、ndistinct、MCVs 和直方图)的更新统计数据。
- 请注意,由于其子表的变化,autovacuum 目前无法处理父表的分析。 在其子表内容发生重大变化后,应手动 ANALYZE 父表,例如在 DROP 或 ALTER..DETACH/ATTACH/UN/INHERIT 之后,或批量 DELETE 或 UPDATE 或许多 INSERT 之后。
- VACUUM 相关表以避免膨胀并设置 relallvisible;
- REINDEX 相关索引 - 解决死索引元组、膨胀,新索引将按堆 TID 的顺序包含条目;请注意,这将阻塞查询(除非你在 v12+ 中使用 REINDEX CONCURRENTLY;另请参阅 pg_repack)
- 检查你的主要 GUC 设置,确保它们被设置为合理的值(有关其他提示,请参阅 调整你的 PostgreSQL 服务器)
- shared_buffers 应为可用 RAM 的 10% 到 25%
- effective_cache_size 应为可用 RAM 的 75%
- 测试是否可以用更小的查询或不同的查询参数重现问题;
- 测试更改 work_mem:将其增加到 8MB、32MB、256MB、1GB。这有影响吗?
- 对于 Insert/Update/Delete 查询,你还应该尝试配置你的 WAL
- 如果可能,将 pg_wal 移到单独的存储设备上
- 增加 max_wal_size 到 2GB 或更大(假设你有磁盘空间)
需要包含的信息
请计划花费约 30 分钟时间收集所需的信息并准备你的问题。成千上万的人会看到它,但如果你没有让别人很容易帮助你,他们可能不会回复。如果写得好,并提供所需的信息,大多数请求都会收到有帮助的回复。甚至有些会导致错误修复或其他补丁。但如果你没有付出很大的努力来提供尽可能多的相关信息,你就很难从社区获得很多免费帮助。
Postgres 版本
请提供你使用的确切服务器版本(SELECT version();
是一个获取它的简单方法)。规划器的行为在每个版本中都会发生变化,所以这一点很重要。
操作系统+版本
什么操作系统/版本? 至少对于 linux,你可以通过运行以下命令来获取发行版:tail /etc/*release
完整的表和索引模式
发布查询中引用的所有表和索引的定义。如果查询涉及视图或自定义函数,我们也需要这些定义。 运行 psql 命令 "\d table",其中 table 是问题查询中引用的表/视图/索引。
表元数据
除了表定义之外,请还发布表中的近似行数。
- SELECT relname, relpages, reltuples, relallvisible, relkind, relnatts, relhassubclass, reloptions, pg_table_size(oid) FROM pg_class WHERE relname='TABLE_NAME';
该表是否有任何不寻常之处?
- 包含大对象
- 在多个列中具有高比例的 NULL 值
- 经常收到大量 UPDATE 或 DELETE 操作
- 正在快速增长
- 拥有许多索引
- 使用可能正在执行数据库函数的触发器,或直接调用函数
EXPLAIN (ANALYZE, BUFFERS),不仅仅是 EXPLAIN
EXPLAIN (ANALYZE, BUFFERS, SETTINGS)
告诉我们查询是如何实际执行的,而不仅仅是它是如何被规划的。这是找出规划器是否错误(如果有的话)的重要信息。 例如:EXPLAIN (ANALYZE, BUFFERS) select * from tablename;
如果你无法运行 EXPLAIN (ANALYZE, BUFFERS) 因为查询从未完成,那就说明这一点。
- 如果你的邮件客户端可能弄乱格式,最好将输出作为单独的文件附加。(否则,人们可能会因为需要在阅读前重新格式化邮件而却步于帮助你)。
- 或者,将你的
EXPLAIN (ANALYZE, BUFFERS, SETTINGS)
结果粘贴到 explain.depesz.com 并发布到结果页面的链接。我们非常喜欢这样,因为它使计划更容易阅读和检查。 - 在执行 EXPLAIN 之前打开 track_io_timing。如果你以超级用户身份登录,可以通过执行
SET track_io_timing = on;
为当前会话打开 track_io_timing。 - 如果使用的是 PostgreSQL v11 或更早版本,SETTINGS 不受支持,你应该还提供所有非默认设置的列表。请参阅 服务器配置。
历史
这个查询一直都很慢,还是最近才变得更慢?如果查询的计划/执行以前有所不同,你有那些查询计划的副本吗?除了数据积累之外,你的数据库是否发生了任何变化?
硬件
请发布有关你的硬件平台的基本信息。如果你的硬件的任何部分都不寻常,请提供有关这些部分的详细信息。请参阅 报告问题的指南,了解哪些硬件信息是有用的。
硬件基准测试
- 运行 bonnie++ 或其他驱动器速度测试,看看你的性能问题是否仅仅是基于硬件的。例如,无论你如何调整查询,RAID-5 配置都永远不会有快速的插入/更新操作。
- bonnie++ -f -n0 -x4 -d /var/lib/pgsql
- 测试存储 postgres 数据文件的设备的顺序读取速度,运行多次。如果你为 WAL 或 tmp 或多个表空间使用单独的驱动器,请为每个驱动器运行多次。128*$RANDOM/32 是 128GB,如果你有超过 ~64GB 的 RAM,则需要相应地增加。32K 是 32GB,如果你的驱动器非常快(或非常慢),则需要增加。如果你的数据库非常小,这可能不是一个好的测试(但在这种情况下,驱动器速度可能并不重要)。
- time dd if=/dev/sdX2 of=/dev/null bs=1M count=32K skip=$((128*$RANDOM/32))
维护设置
你是否运行 autovacuum?如果是,设置是什么?如果不是,你是否正在进行手动 VACUUM 和/或 ANALYZE?频率如何? SELECT * FROM pg_stat_user_tables WHERE relname='table_name';
WAL 配置
对于数据写入查询:你是否将 WAL 移到不同的磁盘?更改了设置?
GUC 设置
你更改了哪些数据库配置设置?它们的值是什么?(这些设置包括 "shared_buffers"、"work_mem"、"enable_seq_scan"、"effective_io_concurrency"、"effective_cache_size" 等)。请参阅 服务器配置,了解一个有用的查询,该查询将以比发布你的 postgresql.conf 文件的部分内容更容易阅读的格式显示你所有非默认数据库设置。
统计:n_distinct, MCV, 直方图
对检查导致错误连接计划的统计数据很有用。 SELECT (SELECT sum(x) FROM unnest(most_common_freqs) x) frac_MCV, tablename, attname, inherited, null_frac, n_distinct, array_length(most_common_vals,1) n_mcv, array_length(histogram_bounds,1) n_hist, correlation FROM pg_stats WHERE attname='...' AND tablename='...' ORDER BY 1 DESC;
启用日志记录
一些建议的初始值
- log_min_duration_statement = '2222ms'
- log_autovacuum_min_duration = '9s'
- log_checkpoints = on
- log_lock_waits = on
- log_temp_files = 0
- log_destination = 'stderr,csvlog'
- log_rotation_age = '2min'
- log_rotation_size = '32MB'
- logging_collector = on