如何在 PostHog ClickHouse 中创建物化列加速 JSON 属性查询?
2026/9/10 5:39:17 网站建设 项目流程

如何在 PostHog ClickHouse 中创建物化列加速 JSON 属性查询?

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

PostHog 把事件的 JSON 数据存在 ClickHouse 的字符串列中,查询时再读取并解析,这类“宽列”(fat column)的读取开销很大,慢查询常出现在对$browser_language这类 JSON 属性做过滤的场景。物化列(materialized columns)把 JSON 中指定的属性预先物化成磁盘上的独立列,官方手册给出的收益是:读取这些列最快可比普通 JSON 属性快 25 倍(up to 25x)。

本文的任务很明确:为高频使用的属性创建物化列,并用回填(backfill)让历史数据也走新列。适用前提是你的实例运行着 PostHog 的 ClickHouse 集群,并且你需要区分两条路径——PostHog 生产环境走 Dagster 作业,自建/本地环境走仓库提供的 Django 管理命令。

先确认:为什么必须回填才生效

物化列创建后只对新写入的数据立即生效。要让已有数据也受益于新列,必须执行回填,而回填会显著增加集群负载,官方手册明确建议在周末执行。手册原文指出:“materialized columns also require backfilling the materialized columns to be effective - an operation best done on a weekend due to extra load it adds to the cluster.”

所以任何创建物化列的计划都要包含两个决定:选哪些属性回填多少天的历史数据

路径一:依赖自动物化(云端默认行为)

PostHog 有一个 cron 任务,会分析上周运行的慢查询,找出其中用到的属性并自动物化其中一部分,实现代码在 analyze.py。相关开关通过环境变量与实例设置控制(手册指向 PostHog 的环境变量文档与 instance settings)。

需要注意:这个 cron 经常因为集群问题或正在进行的数据迁移而被临时禁用,因此它不能作为你“保证某列被物化”的依据。如果你的目标属性不在自动物化范围内,或者你希望控制回填窗口,就走下面两条手动路径。

路径二(手动):用 Django 管理命令创建

仓库提供了materialize_columns管理命令(源码),在 PostHog 后端环境中执行。它有两种模式:

  • 指定--property:直接物化你列出的属性,跳过慢查询分析
  • 不指定--property:按--analyze-period指定的时间窗口分析慢查询,自动挑选属性,受--max-columns限制单次物化数量。

1. 先 dry-run 预览计划

--dry-run只打印计划,不修改任何表,日志会输出Dry run: No changes to the tables will be made!

python manage.py materialize_columns \ --property '$browser_language_prefix' '$app_namespace' \ --property-table events \ --table-column properties \ --backfill-period 90 \ --dry-run

--property支持在一个参数组内传多个属性(命令帮助中的示例形式是--property abc '$.abc.def'),$开头的属性名建议加引号。

2. 确认后实际执行

去掉--dry-run重复执行同一命令即可。执行时日志会输出实际操作的表和属性:

Materializing column. table=events, property_name=['$browser_language_prefix', '$app_namespace']

3. 参数说明

参数取值 / 默认用途
--property属性名列表要物化的属性;提供后跳过自动分析
--property-tableevents(默认)或person--property所在的表
--table-columnproperties(默认)、group_propertiesperson_properties物化来源的 JSON 列
--backfill-period天数为默认值(对应MATERIALIZE_COLUMNS_BACKFILL_PERIOD_DAYS环境变量),0表示不回填回填多少天历史数据
--dry-run布尔开关只打印计划,不执行变更
--min-query-time/--analyze-period/--analyze-team-id/--max-columns对应同名环境变量或默认值仅在未指定--property的自动分析模式下生效

列名由系统生成:events表的物化列以mat_为前缀,person表以pmat_为前缀,属性名中的特殊字符会被替换(见 columns.py 的_materialized_column_name)。同时会在数据表上为新列创建minmax数据跳过索引,用于加速过滤。

路径三(PostHog 生产环境):通过 Dagster 作业

PostHog 在生产环境中用 Dagster 作业创建物化列:job 名为create_materialized_column,位于team-clickhouselocation,EU 与 US 两个区域各有对应的 playground 入口(手册中给出了两个区域各自的链接,见 手册原文)。

在 playground 中配置create_materialized_columns_op,手册给出的示例配置(作业源码):

ops: create_materialized_columns_op: config: backfill_period_days: 90 dry_run: false properties: - $browser_language_prefix - $app_namespace table: events table_column: properties

配置项含义(手册原文):

  • table:要物化的 ClickHouse 表,例如eventsperson
  • table_column:存放属性的 JSON 列,例如propertiesperson_propertiesgroup_properties
  • properties:要物化成列的属性名列表;
  • backfill_period_days:回填多少天历史数据(手册示例为90);
  • dry_run:设为true可预览将物化什么而不做任何变更。

该 op 还支持is_nullable(默认true),控制生成的列是否为Nullable类型。

验证结果

1. 检查列是否已创建

物化列的 comment 带有column_materializer::标记,项目实现就是靠这个标记识别物化列的(columns.py)。你可以在 ClickHouse 中查询:

SELECT name, type, comment FROM system.columns WHERE database = currentDatabase() AND table = 'events' AND comment LIKE '%column_materializer::%';

能查到刚创建的对象即说明列已建好,type通常为Nullable(String)--nullable默认开启时)。

2. 检查索引

默认会创建minmax_<列名>索引,可用同一实现中使用的查询方式核对:

SELECT name, table FROM system.data_skipping_indices WHERE database = currentDatabase() AND table = 'events' AND name LIKE 'minmax_%';

3. 回填状态判断

回填走的是 ClickHouse mutation(ALTER TABLE ... UPDATE col = col WHERE timestamp > <截止日期>),提交后立即返回、在后台按分区更新。因此“命令成功返回”不等于历史数据已全部回填完成,文档没有给出统一的回填完成判定 SQL,建议结合集群的 mutation 状态自行跟踪。

限制与后续操作

  • 回填负载:无论哪条路径,回填都会额外读写大量数据,官方建议安排在周末。
  • 自动物化可能缺席:cron 会因集群问题或数据迁移被禁用,手动路径不受影响。
  • 启用/禁用/删除:物化列不是永久的。仓库提供update_materialized_column命令(源码):
# 启用 / 禁用某个物化列 python manage.py update_materialized_column enable events mat_xxx python manage.py update_materialized_column disable events mat_xxx

disable只把该列标记为禁用(通过列 comment 标记),不动数据;drop会真正执行DROP COLUMN及对应索引(DROP INDEX),是不可逆的删除操作,执行前确认该属性确实不再需要,例如:

python manage.py update_materialized_column drop events mat_xxx

命令执行成功时日志输出Success!。如果你只是想让查询暂时忽略某个物化列,用disable而不是drop

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询