2025年12月27日·阅读约1分钟

用于报表的 PostgreSQL 只读副本:让仪表盘保持快速

使用 PostgreSQL 只读副本做报表,让仪表盘在副本上运行耗时查询,从而保护主库不被慢查询、突发负载和锁争用影响,保持仪表盘和事务都快速。

用于报表的 PostgreSQL 只读副本:让仪表盘保持快速

为什么报表会拖慢主数据库

一种常见的情形是:应用大部分时间运行正常,但有人打开仪表盘后,结账、登录或支持工具突然变慢。系统并没有“宕机”,只是变慢了。这通常是主数据库同时被两类负载拉扯造成的。

事务(日常应用工作)通常短小而有针对性。它们读取或更新少量行,使用索引并快速完成,以便其他请求可以继续。报表查询则不同:它们经常扫描大量数据、连接多张表、排序并分组结果,计算跨天或跨月的汇总。即便这些查询并未直接阻塞写入,它们仍会消耗应用所需的共享资源。

下面是仪表盘常常如何影响 OLTP 数据库的方式:

  • 大量读取争抢 CPU、内存和磁盘 I/O
  • 大规模扫描将“热”页从缓存挤出,使普通查询变慢
  • 大型排序和 GROUP BY 可能溢写到磁盘,造成负载突增
  • 长时间运行的查询增加争用,使峰值持续更长时间
  • 即席过滤(日期范围、分段)让负载难以预测

只读副本是一个独立的 PostgreSQL 服务器,会持续复制主库的数据并可以提供只读查询服务。把仪表盘指向副本进行报表查询,就能把这些繁重工作放到别处,让主库专注于快速事务处理。

需要提前明确的期望:副本能帮忙处理读取,但不能处理写入。你不能安全地把 INSERT/UPDATE 发送到普通副本,而且副本的数据通常会比主库滞后一点,因为复制需要时间。对许多仪表盘来说,这是合理的折中:换取稳定的应用性能,接受数据稍有延迟。

如果你构建内部仪表盘(例如在 AppMaster 中),这种划分常常很自然:应用继续写入主库,而报表页面向副本发起查询。

用通俗的话解释 PostgreSQL 的只读副本如何工作

PostgreSQL 的只读副本是第二个数据库服务器,会保持主数据库的近实时副本。主库负责写操作(INSERT、UPDATE、DELETE),副本主要提供读取(SELECT),这样报表查询就不会与日常事务竞争。

一分钟理解主库与副本的区别

把主库想象成拥挤商店的收银员:它必须保持响应,因为每笔交易都会更新库存、付款和订单。副本更像展示屏,展示总数和趋势。它观察收银员的操作并在稍后更新自己的视图。

在底层,PostgreSQL 通过传送主库发生变化的流并在副本上回放来复制变更。这意味着副本最终会拥有相同的数据库结构和数据,只是稍有滞后。

在实际层面,复制会传送:

  • 表数据(行)
  • 索引变更(以便查询能使用相同索引)
  • 模式更改(比如新列、新表以及多种迁移)
  • 通过正常 SQL 发起的大多数其他数据库变更

副本不会解决的问题:它不会让大量写操作变得更便宜,也无法修复由糟糕模式或缺失索引导致的慢查询。如果你的仪表盘查询在副本上扫描了巨量表,它仍然会很慢。不同的是,它不会同时拖慢结账流程。

这就是为什么用于报表的 PostgreSQL 只读副本很受欢迎:它们把 OLTP 工作(快速、频繁的事务)和 OLAP 风格的工作(较长的读取、分组与汇总)分离开来。如果你构建内部仪表盘或管理面板(例如在 AppMaster 中),把报表页面指向副本通常是保持两端都高兴的最简单方法。

适合放到副本上的常见报表工作负载

一个简单规则:如果查询主要是读取大量数据并做汇总,那它很适合在副本上运行。使用用于报表的 PostgreSQL 只读副本可以保护结账流程、登录和其他事务性工作不被仪表盘的重负载影响。

最常见的仪表盘模式是大范围的日期加上少量过滤。像“过去 90 天按地区、产品和渠道”这样的查询可能轻易触及数百万行,即便最终图表只显示 12 个柱状。这样的扫描会与主库争抢磁盘读取和缓存空间。

适合在副本上运行的工作负载

大多数团队会先把这些放到报表库:

  • 跨多表的大型连接(orders + items + customers + refunds)
  • 像 SUM、COUNT DISTINCT、百分位、分群的聚合计算
  • 排序和分组大结果集的长时间运行查询
  • 每小时/每天运行、重复同样重计算的定期报表
  • 探索性 BI 会话,用户反复点击并重跑变体

即便查询是“只读”,它仍会消耗 CPU、内存和 I/O。大型 GROUP BY 操作会把其他查询挤出内存。重复的扫描会扰动缓冲缓存,使主库更频繁地从磁盘读取。

连接行为也很重要。许多 BI 工具为每个用户打开多条连接,每几分钟刷新瓦片,并运行后台抽取。这会导致连接和并发查询的突增。副本为这些突发提供了更安全的落脚点。

举个简单例子:运营仪表盘在 9:00 AM 加载,50 人同时打开。每个页面视图触发若干个小部件,每个小部件运行带不同过滤条件的查询。在主库上,这种突发会让订单创建变慢。在副本上,仪表盘可以变慢或稍有滞后,但事务保持快速。

如果你在像 AppMaster 这样的平臺内构建内部仪表盘,只要大家理解数据可能滞后几秒(或几分钟),把报表屏幕指向副本连接通常是个简单可行的方案。

权衡:新鲜度与速度(复制滞后)

只读副本之所以能让仪表盘保持快速,是因为它把报表查询从主库上移走。代价是副本通常会稍有滞后。这个延迟叫做复制滞后(replication lag),也是用于报表的 PostgreSQL 只读副本的主要权衡点。

用户会注意到的通常很简单:今天的数据会稍微少一些,最新订单缺失,或图表晚几分钟才更新。大多数情况下,人们不介意周趋势滞后几分钟,但如果“支付刚成功”的视图显示错误,那就会引发抱怨。

滞后发生在主库产生变更的速度超过副本接收并回放这些变更的速度时。常见原因包括写入突发(秒杀、导入)、网络带宽受限、副本磁盘慢,或副本在应用变更时与长时查询争抢 CPU 和 I/O。

选择可接受滞后的一个实用方法是根据仪表盘支持的决策来定:

  • 高管 KPI 仪表盘:几秒到几分钟通常可以接受。
  • 运营队列(发货、支持):目标是接近实时,通常以秒计。
  • 财务结算或审计:在受控快照上运行,而非“实时”。
  • 面向客户的“我的最近订单”:接近实时,或直接使用主库。

简单规则:如果报表必须包含最新提交的事务,就必须访问主库(或某个保证实时性的系统)。典型例子包括结账时的库存可用性、风控检查以及任何会触发即时动作的场景。

示例:销售团队的仪表盘可以安全地从副本读取并每分钟刷新。但“订单确认”页面应该从主库读取,因为在刚下单后显示“未找到订单”将招致大量支持工单。

如果你的应用或无代码工具允许选择数据库连接(例如在 AppMaster 中把只读屏幕指向副本),可以在不改变 UI 构建方式的情况下应用这种划分。

步骤指南:为仪表盘设置只读副本

将读取与写入分离
生成可扩展的后端和 UI,然后将报表页面指向你的副本。
开始构建

为仪表盘设置副本主要是事先做出几个明确选择,然后把报表流量与主库分离。

1)先确定合适的拓扑

从拓扑开始。对于单一 BI 工具和少量仪表盘,一台副本通常就足够。多台副本适合有大量分析人员或多个工具全天访问数据的情形。如果用户远离主机区域,可考虑区域副本以降低延迟,但这也会增加监控点。

接下来选择同步或异步复制。同步复制能保证最新性,但可能会拖慢写入,这对很多团队来说会抵消使用副本的意义。对于仪表盘,异步复制是常见选择,只要大家接受数据可能会有少许滞后。

2)把副本按报表服务器来构建

副本不是廉价的生产拷贝。报表查询通常需要更多 CPU、更多用于排序的内存,以及更快的磁盘以应对扫描。

这是一个用于构建用于报表的 PostgreSQL 副本的实用流程:

  • 决定需要多少副本以及它们应该部署在哪(同一区域或更靠近用户)。
  • 根据仪表盘能容忍多少延迟选择异步还是同步。
  • 为读密集型工作预配资源(CPU、内存和磁盘 IOPS 通常比存储大小更重要)。
  • 为报表用户和工具创建单独的只读凭证。
  • 将仪表盘查询路由到副本(配置你的应用、BI 工具或小型报表服务使用副本连接)。

路由之后用一个简单测试验证:运行一个已知的重查询,确认它不再出现在主库的活动中。

如果你用 AppMaster 构建应用,通常意味着为报表定义单独的数据库连接并仅用于仪表盘端点,这样结账和其他事务流程就保有快速通道。

报表用户的访问控制与安全

只读副本很适合仪表盘,但仍需要保护措施。把它当作共享资源:给报表工具足够的访问权限去完成工作,但要限制单个坏查询能造成的影响。

从为报表创建单独数据库用户开始。不要重用应用的主凭证,即便你指向的是副本。这样更方便审计活动、轮换密码并收紧权限。

一个适合大多数团队的简单方法如下:

-- Create a dedicated login
CREATE ROLE report_user LOGIN PASSWORD '...';

-- Allow read-only access to a schema
GRANT CONNECT ON DATABASE yourdb TO report_user;
GRANT USAGE ON SCHEMA public TO report_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO report_user;

-- Put safety limits on the role
ALTER ROLE report_user SET statement_timeout = '30s';
ALTER ROLE report_user SET idle_in_transaction_session_timeout = '15s';

接下来,要控制连接风暴。仪表盘和 BI 工具喜欢打开许多连接,尤其是多个小部件同时刷新时。把报表连接数在数据库和连接池处限制住,并与事务性流量分离。

一个实用清单:

  • 使用只读用户(无 INSERT/UPDATE/DELETE,无模式更改)。
  • 为该角色设置长查询和空闲会话的超时限制。
  • 限制报表用户的最大连接数到一个安全值。
  • 仅授权仪表盘需要的模式和表的访问权限。
  • 在报表视图中屏蔽或排除敏感列(PII、密钥、令牌)。

如果需要展示部分客户数据,不要指望“人们会小心”。创建隐藏或哈希敏感字段的报表视图,或维护一个策划过的报表模式。在团队使用 AppMaster 构建仪表盘时,使用副本连接字符串和专用报表用户,这样生成的应用可以安全读取而不触及生产写权限。

这些控制措施能让用于报表的 PostgreSQL 只读副本更快、更可预测,也更难被滥用。

让仪表盘不出意外的监控要点

更安全的报表访问
通过应用流程添加只读用户和超时等保护措施。
试用 AppMaster

副本只有在表现可预测时才有帮助。通常让团队惊讶的两件事是静默的复制滞后(仪表盘看起来“有问题”)和副本资源突增(仪表盘变慢)。监控应在用户发现之前捕获这两种情况。

先从测量滞后并就“足够新鲜”达成一致开始。对很多报表仪表盘来说,30 到 120 秒是可以接受的。对一些(如库存或风控),即便 5 秒也可能太长。无论选择什么,把它做成一个可见的指标并在超出阈值时告警。

以下是用于监控用于报表的 PostgreSQL 只读副本的一些实际信号:

  • 复制滞后(时间与字节)。在超过阈值几分钟后触发告警,而不是仅对单次峰值告警。
  • 副本健康:在报表高峰期间的 CPU、内存压力和磁盘读 I/O。
  • 副本的连接饱和(过多仪表盘会话会让数据库看起来“慢”)。
  • 在副本上的慢查询,使用副本自身的统计与日志(不要假设主库能反映全部情况)。
  • 自动清理(autovacuum)和臃肿(bloat)。当表或索引臃肿时,读取性能会下降。

对慢查询的追踪尤为重要。一个常见失误是:某个仪表盘在测试中表现良好,但在生产中变成“全表扫描节”。确保副本有和主库相同的监控,包括按总耗时和平均耗时排序的顶级查询。

最后,提前决定当副本不可用或滞后过大时你的应用如何处理。选择一种一致的行为并实现它:

  • 当滞后超阈值时显示“数据延迟”横幅。
  • 暂时禁用最重的图表,仅保留轻量摘要。
  • 回退使用缓存结果(例如最近 15 分钟的缓存)。
  • 对特定页面将关键读取路由回主库。
  • 在副本恢复前将仪表盘置为只读维护模式。

如果你在 AppMaster 中构建内部仪表盘,把副本当作独立数据源:单独监控它,并设计仪表盘在新鲜度或性能下降时能够优雅降级。

常见错误与陷阱

在不压垮数据库的情况下发布报表
使用单独的只读数据库连接快速创建内部报表页面。
开始构建

只读副本有帮助,但不是“报表免费”的魔法按钮。大多数副本问题来自把它当作无限的分析仓库,然后在仪表盘变慢或数据不对时感到惊讶。

一个容易被忽视的点:副本也会被压垮。几次广泛的表扫描、重连接或 "SELECT *" 导出都会把 CPU 和磁盘推到极限并导致超时。如果副本使用比主库更小的硬件(为节省成本常见),性能下降会更快显现。

下面是最容易造成痛苦的陷阱:

  • 把关键实时页面路由到副本。如果仪表盘用于确认刚完成的结账或展示实时库存,复制滞后会让数据看起来缺失。
  • 允许 BI 工具打开过多连接。有些工具会同时刷新许多瓦片,每个瓦片可能打开自己的会话。连接峰值会把副本压垮,即便单个查询看起来不大。
  • 认为有索引就万事大吉。索引不能修复会拉出数百万行、在错误键上分组或无边界连接的查询。查询形状和数据量比增加索引更重要。
  • 忽视“早上快”不等于“永远快”。一个在早上运行良好的查询可能随着数据增长或多人同时刷新同一报表而变慢。
  • 未为故障切换行为做计划。故障切换期间,副本可能会被提升或替换,如果不计划好切换,客户端可能会遇到只读错误或访问旧端点。

一个现实例子:你的 BI 工具每分钟刷新一次“今日订单”页面,每次刷新运行 5 个重查询,20 人同时打开,就会产生每分钟 100 次重查询突发。主库可能保持安全,但副本可能会撑不住。

如果你在像 AppMaster 这样的平臺上构建内部仪表盘,把报表数据库作为独立目标对待,设置自己的连接限制和“所需新鲜度”规则,避免用户无意中依赖滞后数据。

能让副本上报表更快的设计模式

只读副本给了你喘息的空间,但并不会自动让每个仪表盘都变快。最佳效果来自于让报表查询做更少、更可预测的工作。这些模式对用于报表的 PostgreSQL 只读副本特别有效,因为它们减少了大规模扫描和重复聚合。

把“报表层”分离出来

考虑一个专用的报表模式(例如 reporting),包含稳定的视图和辅助表。这能阻止 BI 工具直接访问原始事务表,并给你一个集中优化的地方。良好的报表视图还能隐藏复杂连接,使仪表盘查询保持简单。

预聚合昂贵的部分

如果某个仪表盘整天重复计算相同的总数(每日收入、按状态的订单、热销商品),就不要在每次加载页面时都从头计算。构建汇总表或物化视图,存储已经分组好的数值。

常见选项:

  • 按日或按小时的汇总(按日期、地区、渠道)
  • “最新已知”快照表(库存、账户余额)
  • Top-N 表(热销商品、重要客户)
  • 为更快过滤而进行非规范化的事实表

按计划刷新耗时指标

用定时任务在离峰时段刷新预聚合。如果业务能接受“每 5 分钟更新一次”,你就能用小延迟换取更快的仪表盘。对超大数据集,增量更新(仅处理自上次运行以来的新行)通常比全量刷新便宜得多。

缓存高频点击的内容

如果相同的仪表盘小部件被重复请求,把结果在应用层短时缓存(30 到 120 秒通常够用)。例如“今日销售”瓦片可以按公司或门店做缓存。在像 AppMaster 这样的工具里,这种缓存通常更容易加在为仪表盘提供数据的 API 端点上。

一个简单规则:如果一个查询既慢又热门,要么预聚合它,要么缓存它,最好两者都做。

一个现实示例:在不影响结账的情况下做销售报表

跨平台的单一仪表盘
创建可在移动端和 Web 上统一使用、从同一报表数据库读取的仪表盘。
在 AppMaster 中构建

想象一个小型电商应用。主数据库全天处理登录、购物车、支付和订单更新。与此同时,团队需要一个显示每小时收入、热销商品和退款的仪表盘。

在任何改动前,仪表盘在主库上运行重查询。临近月末,某人打开“过去 30 天按产品”的图表,它扫描了大量 orders 表。结账开始变慢,因为这些报表查询与事务争抢 CPU、内存和磁盘读取。

解决方法很直接:把仪表盘读取移动到副本。使用用于报表的 PostgreSQL 只读副本,主库继续快速写入,副本负责长时间的读取。仪表盘使用副本的连接字符串,而不是主库。

团队还制定了清晰的新鲜度规则,避免有人期待完全天实时数据:

  • 在仪表盘上显示“数据更新于 X 分钟前”
  • 平时允许最多 5 分钟的延迟
  • 如果滞后超过 10 分钟,切换到“延迟模式”并暂停最重的图表
  • 结账和订单更新始终访问主库

改动后效果明显。即便在报表高峰期,结账仍然稳定,图表加载快速,因为它们不再与事务争抢资源。

需要明确告诉用户的是:仪表盘是“近实时”的,而不是最后几秒的权威数据。如果有人需要精确的对账数据,应运行定时导出或日终报表。

如果你用像 AppMaster 这样的平臺构建应用,从一开始就把报表作为独立的只读连接对待,这样你的事务流程保持可预测。

快速检查与下一步

在把仪表盘指向副本前,做一个快速检查。几个小设置和习惯可以避免最常见的意外:数据陈旧、超时和意外写入。

在向副本发送流量前要配置的快速清单:

  • 让报表连接只读(使用专用用户并强制只读事务)。
  • 将报表与应用流量分离(单独的连接池和合理的连接限制)。
  • 确认副本有仪表盘依赖的索引(副本会复制索引,但请检查是否遗漏了最近的变更)。
  • 为报表查询设置语句和锁超时,避免某个坏图表挂起一切。
  • 验证图表能容忍小延迟(显示“截至”时间戳或按分钟取整)。

一旦流量开始流动,把监控当作每周的轻量例行工作,而不是火警演习。尤其是对于用于报表的 PostgreSQL 只读副本,“昨天可用”在数据量增长时可能很快变化。

每周监控清单(10 分钟):

  • 复制滞后:观察典型滞后和高峰时的最差峰值。
  • 慢查询:按总耗时跟踪主要罪魁。
  • 连接:检查最大连接数、连接池饱和和堆积的空闲连接。
  • 磁盘与 CPU:副本在重扫描时可能受存储瓶颈限制。
  • 失败的查询:查找超时、取消的语句或权限错误。

接下来的步骤多半关乎路由规则与回退计划。决定哪些端点总是可以从副本读取(仪表盘、导出、管理报表),哪些必须保留在主库(任何必须达到秒级最新的页面)。定义当滞后越过限制时如何处理:展示警告横幅、对部分页面回退到主库,或暂时禁用最重的图表。

如果你构建内部仪表盘或管理工具,AppMaster 可以是快速交付的实用方式,同时把报表屏幕指向副本,让核心事务应用继续平稳运行。

容易上手
创造一些 惊人的东西

使用免费计划试用 AppMaster。
准备就绪后,您可以选择合适的订阅。

开始吧
用于报表的 PostgreSQL 只读副本:让仪表盘保持快速 | AppMaster