被低估的 Postgres:Extended Statistics 实现更佳执行计划

发布: (2026年3月19日 GMT+8 04:30)
6 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的文章正文内容,我将把它完整地翻译成简体中文,并保留原有的格式、Markdown 语法以及代码块和链接不变。谢谢!

概述

Underrated Postgres:用于更佳执行计划的扩展统计信息封面图

PostgreSQL 的一个鲜为人知且使用率更低的特性(至少在生产环境中我很少见到)是 扩展统计信息,它用于捕获和编码多列值之间的依赖关系、关联以及可能的组合。

查询规划器通常基于单列统计信息来生成执行计划,但列之间的关系在实际应用中非常常见。我个人本来希望能更早了解这个特性。通常,我会再建一个索引 hoping it improves access patterns, but the cost of all the indexes quickly reaches or even exceeds the size of the original table. 扩展统计信息正是为了解决这个问题——它往往是额外索引的更轻量替代方案。

单列统计的缺陷

PostgreSQL 的查询规划器在估算不同执行计划的成本时严重依赖统计信息。默认情况下,它会收集各个列的统计信息。当列之间相互独立时,这种做法效果很好。然而,在许多实际场景中,列之间是相关的。

考虑一个名为 users 的表,包含 citycountry 两列。如果查询条件是 city = 'Paris'country = 'France',规划器可能会低估返回的行数,因为它假设这两个条件相互独立,将 city = 'Paris' 的概率与 country = 'France' 的概率相乘。实际上,只要城市是巴黎,国家几乎必定是法国。

这种低估会导致规划器选择次优的执行计划(例如选择嵌套循环连接而不是哈希连接),从而导致性能不佳。

输入扩展统计

扩展统计允许您向 PostgreSQL 说明列之间的关系。您可以在多个列上创建统计信息,使规划器能够做出更准确的估计。

创建扩展统计信息

您可以使用 CREATE STATISTICS 命令创建扩展统计信息。以下是一个简单示例:

CREATE STATISTICS city_country_stats (dependencies)
ON city, country
FROM users;

此命令创建的统计信息捕获 users 表中 citycountry 列之间的函数依赖关系。

扩展统计的类型

  • Dependencies – 捕获列之间的函数依赖(例如,city 决定 country)。对具有多个相等条件的查询很有用。
  • N‑Distinct – 估计一组列组合的不同值数量。对 GROUP BY 查询很有用。
  • MCV (Most Common Values) – 存储跨多列的最常见值组合。对具有复杂条件的查询(例如,不等式、OR 子句)很有用。
CREATE STATISTICS complex_stats (dependencies, mcv)
ON col1, col2, col3
FROM my_table;

何时使用扩展统计信息

扩展统计信息在以下情况下特别有用:

  • 当查询在相关列上有多个条件时。
  • 当查询规划器持续低估或高估行数时。
  • 当你考虑仅为改进查询规划而添加多列索引时(扩展统计信息通常是更轻量的替代方案)。

常见陷阱

  • 过度使用 – 不要在每个列组合上创建扩展统计信息。它们会占用存储并增加 ANALYZE 操作的开销。仅在识别出特定查询计划问题时才创建它们。

  • 忘记执行 ANALYZE – 创建扩展统计信息后,必须对表运行 ANALYZE,才能让规划器开始使用它们。

  • 复杂表达式 – 扩展统计目前仅适用于简单列引用,不支持表达式(例如 LOWER(col))。

结论

扩展统计是 PostgreSQL 中一个强大但未被充分利用的功能。通过向查询规划器提供列之间关系的信息,您可以显著提升复杂查询的性能,而无需额外的索引开销。

  • 使用 CREATE STATISTICS 捕获依赖关系、n‑distinct 值或 MCV。
  • 针对规划器估计不准的特定查询进行优化。
  • 在创建统计信息后记得对表执行 ANALYZE
0 浏览
Back to Blog

相关文章

阅读更多 »

阻止多租户应用中的数据泄漏

为什么仅靠应用逻辑不足以满足需求:数据库级行级安全的案例 你已经构建了一个强大的多租户 SaaS。你已经实现了 tenant_id f…