IO - DataFileRead
当由于数据页在共享内存中不可用,连接等待后端进程从存储中读取所需缓冲区页时,会发生 DataFileRead
事件。
所有查询和数据处理 (DML) 操作都会访问缓冲区中的页面。可以诱导读取的语句包括 SELECT
、UPDATE
和 DELETE
。例如,UPDATE
可以从表或索引中读取页面。如果请求或更新的页面不在共享缓冲区中,则此读取可能会导致 DataFileRead
事件。
由于共享缓冲区是有限的,所以它可以填满。在这种情况下,对不在内存中的页面的请求会强制数据库从磁盘中读取数据块。如果 DataFileRead
事件频繁发生,您的共享缓冲区可能太小,从而无法容纳您的工作负载。对于读取大量不适合缓冲区的行的 SELECT
查询,此问题很严重。有关缓冲区的更多信息,请参阅共享缓冲区。
DataFileRead
事件的常见原因包括以下各项:
-
连接激增
您可能会发现多个连接生成相同数量的
DataFileRead
等待事件。在这种情况下,DataFileRead
事件可能会发生激增(突然大幅度增加)。 -
执行顺序扫描的 SELECT 和 DML 语句
您的应用程序可能正在执行新的操作。或者,现有的操作可能会因为新的执行计划而发生变化。在这种情况下,请查找具有更大的
seq_scan
值的表(特别是大表)。通过查询pg_stat_user_tables
查找它们。要跟踪生成更多读取操作的查询,请使用插件pg_stat_statements
。 -
适用于大型数据集的 CTAS 和 CREATE INDEX
我们把
CREATE TABLE AS SELECT
语句简称为 CTAS。如果您使用大型数据集作为源来运行 CTAS,或者在大型表上创建索引,则可能会发生DataFileRead
事件。创建索引时,数据库可能需要使用顺序扫描读取整个对象。当页面不在内存中时,CTAS 会发生DataFileRead
事件。 -
导入大量数据
当您的应用程序导入大量数据时,
ANALYZE
操作可能会更频繁地发生。ANALYZE
进程可以由 Autoanalyze 启动程序触发,也可以手动调用。ANALYZE
操作可以读取表的子集。必须扫描的页数通过将 30 乘以default_statistics_target
值进行计算。有关更多信息,请参阅 PostgreSQL 文档。default_statistics_target
参数接受 1 到 10000 之间的值,其中原定设置值为 100。 -
资源匮乏
如果消耗了实例网络带宽或 CPU,
DataFileRead
事件可能会更频繁地发生。
根据等待事件的原因,我们建议采取不同的操作。
假设您确定了正在生成 DataFileRead
等待事件的特定查询。您可以使用以下方法识别它们:
- 系统视图,例如扩展插件
pg_stat_statements
提供的视图 - 系统视图
pg_stat_all_tables
,如果它定期显示物理读取数量增加 pg_statio_all_tables
视图,如果它显示_read
计数器正在增加
我们建议您确定这些查询的谓词(WHERE
子句)中使用了哪些筛选条件。请遵循以下准则:
-
运行
EXPLAIN
命令。在输出中,确定使用的扫描类型。顺序扫描不一定表示存在问题。与使用筛选条件的查询相比,使用顺序扫描的查询自然会产生更多的DataFileRead
事件。了解
WHERE
子句中列出的列是否已编入索引。如果没有,请考虑为此列创建索引。这种方法避免了顺序扫描并减少了DataFileRead
事件。如果某个查询具有限制性筛选条件并且仍然生成顺序扫描,请评估是否使用了正确的索引。 -
了解查询是否正在访问非常大的表。在某些情况下,对表进行分区可以提高性能,从而允许查询只读取必要的分区。
-
检查联接操作的基数(总行数)。请注意您在筛选条件中为您的
WHERE
子句传递的值的限制性。如果可能,请优化查询以减少在计划的每个步骤中传递的行数。
维护操作(例如 VACUUM
和 ANALYZE
)非常重要。我们建议您不要将其关闭,因为您会找到与这些维护操作相关的 DataFileRead
等待事件。以下方法可以最大限度地减少这些操作的影响:
- 在非高峰时段手动运行维护操作。此方法可防止数据库达到自动操作的阈值。
- 对于非常大的表,请考虑对表进行分区。这种方法减少了维护操作的开销。数据库只访问需要维护的分区。
- 当您导入大量数据时,请考虑禁用自动分析功能。
当以下公式为真时,系统会自动为表触发 Autoanalyze 功能。
pg_stat_user_tables.n_tup_ins > (pg_class.reltuples x autoanalyze_scale_factor) + autoanalyze_base_threshold
视图 pg_stat_user_tables
和目录 pg_class
有多个行。一行可以对应于表中的一行。这个公式假设 reltuples
适用于特定的表。参数 autoanalyze_scale_factor
(原定设置为 0.20)和 autoanalyze_base_threshold
(原定设置为 50 个元组)通常在全局范围内为整个实例设置。但是,您可以为特定表设置不同的值。
您在监控数据库运行状态时,可能会发现数据库连接数指标激增。这种增加表示与数据库的连接数量有所增加。我们建议采取以下方法:
-
限制应用程序可与每个实例一起打开的连接数。如果您的应用程序具有嵌入式连接池功能,请设置合理数量的连接。根据实例中的 CPU 可以有效并行处理的数量来确定数量。
-
尽可能利用 PostgreSQL 的热备实例。当您的应用程序运行只读操作时,将这些请求发送到只读实例。此方法将应用程序请求分布到所有读取器节点,从而减少了写入器节点的输入/输出压力。
-
请考虑纵向扩展数据库实例。更高容量的实例类可提供更多内存,这为 PostgreSQL 提供了一个更大的共享缓冲池来容纳页面。较大的大小还为数据库实例提供了更多的 CPU 来处理连接。当生成
DataFileRead
等待事件的操作为写入时,更多的 CPU 会特别有用。