关于 mz-health-check
mz-health-check 是一项通过 MCP Developer endpoint 分析 Materialize 环境的 Skill。它引导用户从 catalog 发现到性能检查,并生成包含健康状况和优化建议的结构化报告。
主要功能
- 01梳理 Materialize 环境清单
- 02指导 Catalog 与 Ontology 查询
- 03分析新鲜度与 hydration 状态
- 04检查内存、CPU 和 worker 偏斜
- 05生成结构化健康报告
适用场景
- 01盘点已部署的 sources、views 和 clusters
- 02排查数据延迟与 hydration 问题
- 03检查资源用量和 worker 负载偏斜
- 04汇总性能发现和优化建议
MCP 相关
该 Skill 指导通过 Materialize MCP Developer endpoint 使用只读查询工具分析环境。它介绍 query_system_catalog,以及在适用时用于查询用户对象和指定 cluster 的 query 工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ materializeinc/ agent-skills --skill mz-health-check安装后在 Claude Code 中输入/mz-health-check确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
mcp-client-connect.mdREADME.mdreferences/queries.mdreport-template.md详细介绍
Materialize 开发者分析
通过 MCP Developer 端点分析 Materialize 环境,并生成一份包含健康状态、性能发现和优化建议的结构化报告。假设 Materialize 版本为 v26.24 或更高。
开发者端点提供两个只读工具:
query_system_catalog— 对系统目录表(mz_*、pg_catalog、information_schema)执行SELECT/SHOW/EXPLAIN。不接受 cluster 参数;即使传入了参数,也会被静默忽略,而非报错。当auto_route_catalog_queries开启(默认设置)时,目录查询会自动路由到目录服务集群(mz_catalog_server);路由器无法在该集群上处理的查询——尤其是所有mz_introspection关系的查询——则会在会话的默认集群上执行(如果设置了角色的cluster默认值,则使用该值;否则使用系统默认值quickstart,除非操作员已修改)。大多数目录查询都应使用此工具。query(在 Materialize v26.30 中添加)— 对角色有权访问的任何对象执行SELECT/SHOW/EXPLAIN,并在必需的cluster参数指定的集群上运行(从 v26.33 起,还可选填cluster_replica)。执行EXPLAIN ANALYZE(必须在 MV/索引所在的集群上运行)以及直接读取用户数据时,必须使用此工具。如果操作员禁用了enable_mcp_developer_query_tool,此工具可能会被隐藏。
将 MCP 客户端连接到 materialize-developer
如果用户询问如何将 MCP 客户端(Claude Code、Cursor、VS Code、Zed、Continue、Windsurf、Claude Desktop)配置、连接或设置为与 materialize-developer 服务通信——包括如何控制连接所用的用户或角色,或如何在不同身份之间切换——请参阅 mcp-client-connect.md。其中介绍了 Emulator、Materialize Cloud 和自管理部署,并提供了各客户端的代码片段、身份验证模式和验证方法。
本 SKILL.md 的其余部分介绍连接后如何分析环境。
发现表和列
不要猜测列名。 系统目录关系包含表、视图、物化视图和源,因此没有单个 SHOW TABLES 或 SHOW VIEWS 能列出所有对象;请使用 SHOW OBJECTS FROM <schema>。mz_internal 中的本体视图描述了目录;请使用这些视图来发现正确的表、列、联接路径和 ID 类型:
| 表 | 说明 |
|---|---|
mz_internal.mz_ontology_entity_types | 现有的目录实体,以及它们映射到的 mz_* 表。 |
mz_internal.mz_ontology_link_types | 实体之间的关系(外键、指标等)。 |
mz_internal.mz_ontology_properties | 每个实体的列名、类型和说明。 |
mz_internal.mz_ontology_semantic_types | 类型化的 ID 域(CatalogItemId、ReplicaId 等)。 |
示例查询:
-- Find the right table for an entity
SELECT name, relation, description
FROM mz_internal.mz_ontology_entity_types
WHERE name LIKE '%source%'
-- Find join paths between entities
SELECT name, source_entity, target_entity, properties, description
FROM mz_internal.mz_ontology_link_types
WHERE source_entity = 'source' OR target_entity = 'source'
-- Find columns for a table
SELECT column_name, semantic_type, description
FROM mz_internal.mz_ontology_properties
WHERE entity_type = 'source_status'
查询前,请使用 SHOW COLUMNS FROM <schema>.<table> 验证列名。
重要规则
服务自身的 initialize 说明中包含目录相关注意事项:例如 last_status_change_at 等列名、mz_cluster_replica_utilization 的副本到集群的 JOIN、本体视图,以及从 v26.40 起的 mz_introspection 路由和 ID 类型。大多数客户端都会转发这些说明;如果你的客户端不会,则可使用 SHOW COLUMNS 作为替代。
mz_introspection 关系需要使用 query 工具
每个 mz_introspection 关系(包括 mz_dataflow_arrangement_sizes)都限定于集群,而 query_system_catalog 无法指定集群,因此通过该工具读取时会落到会话的默认集群:如果该集群恰好有一个副本,你会得到该副本的数据,或者得到空结果,且不会报错;如果有多个副本,读取会失败并提示 log source reads must target a replica;如果没有副本,则会提示 has no replicas available to service request。请使用带 cluster 参数的 query 读取这些关系;对于有多个副本的集群,还要使用 cluster_replica(从 v26.33 起支持,不计费的副本也算),这正是第一个错误要求的操作;第二个错误则无法通过此方式解决。
v26.40 之前的服务器会在其 initialize 指令中要求不要查询
mz_dataflow_arrangement_sizes;这条规则早于 query
工具,此处说明优先于该规则。相关查询、通往目录的联接路径及注意事项,见
references/queries.md 中的 Arrangement Sizes。如果没有
query 工具,请改用下面“内存和资源消耗”部分中的关系。
工作流概览
- 连接 — 确认 MCP Developer 工具可用
- 发现 — 使用本体和目录查询,盘点所有已部署对象
- 分析 — 评估性能指标:新鲜度、水合状态、内存、利用率
- 报告 — 生成包含发现和建议的结构化 Markdown 报告
步骤 1:验证 MCP 连接
确认你可以使用 query_system_catalog 工具。运行一个快速测试:
query_system_catalog: SELECT mz_version() FROM mz_catalog.mz_databases LIMIT 1
query_system_catalog 会拒绝不引用系统目录表的 SELECT,因此单独执行 SELECT mz_version() 会失败,并提示 Query must reference at least one system catalog table,这看起来像是连接故障。
检查客户端提供的工具中是否有 query 工具。使用该工具,你还可以对命名集群上的用户对象运行 EXPLAIN ANALYZE 和查询;如果没有该工具(因为操作员禁用了它,或使用的是 v26.30 之前的版本),则对所有适用的操作使用 query_system_catalog。
如果 query_system_catalog 失败,请检查:
- MCP 服务已在客户端的 MCP 配置中注册(不同客户端使用的文件和键各不相同,详见
mcp-client-connect.md) - 环境中已启用
enable_mcp_developer功能标志 - 身份验证凭据有效
运行查询
每次调用中,两种工具都只接受一条只读语句,不支持 SET,且末尾不能有分号(可以有一个;两个语句会被拒绝)。
结果以不带列名的裸行数组形式返回,所有 AS 别名都会被丢弃,因此请按位置映射列,并让 SELECT 列表保持简短,且按你打算读取的顺序排列。数字会以字符串形式返回,布尔值会以 JSON true/false 形式返回,NULL 会以 null 形式返回;timestamp 和 timestamptz 值会以毫秒级 Unix 纪元时间戳字符串形式返回(1787687415336.000),需要可读时间时,请将它们转换为 text。如果对象不在当前会话所在的数据库中(SHOW database),请使用数据库名称限定对象名,否则语句会因 unknown schema 而失败。响应有大小上限(默认 1 MB),请求也有超时时限(默认 60 秒);两者都可由运维人员配置,超限时都会报错。使用 LIMIT 可以让目录枚举结果不超过上限;它只会减少对单个索引关系的简单读取所需的工作量,不会减少连接查询的工作量。超时会释放此次调用,但查询有时仍会继续运行,因此不要原样重试超时的语句。
query_system_catalog 通过遍历 FROM 子句中的表引用来检查允许列表,因此不含此类引用的语句完全不会经过检查:SHOW TABLES、SHOW COLUMNS、SHOW CREATE 各种形式以及对象级 EXPLAIN ANALYZE 都可以通过检查并指定用户对象(这也是后者会返回空结果的原因,见“Worker Skew”)。仅在缺少 query 时将其作为后备方案;查询用户对象时请使用 query。
过滤系统架构时,务必始终排除:mz_catalog、mz_internal、pg_catalog、information_schema 和 mz_introspection。SHOW SCHEMAS 还会列出 mz_catalog_unstable 和 mz_unsafe,其中不包含任何关系。
步骤 2:发现 — 清点环境
运行发现查询,了解已部署的内容。完整查询集请参见
references/queries.md。发现阶段包括:
环境概览
- Materialize 版本
- 集群和副本——名称、
managed、副本数量和规格。请从mz_clusters开始并 LEFT JOIN 副本,否则没有副本的集群会从清单中消失。非托管集群的size和replication_factor为 NULL;未计费的支持副本列在mz_internal.mz_internal_cluster_replicas中,与其他副本一样计数。 - 正在使用的架构
已部署对象清单
- 源:类型(Kafka、Postgres、MySQL、Webhook 等)、集群分配、状态。
mz_sources还会为每个子源和progress集合各包含一行,因此统计源数量前,请先筛选type NOT IN ('subsource', 'progress')。 - 物化视图:集群分配、索引、依赖关系
- 视图:(非物化视图)及其使用模式
- Sink:类型、目标位置、集群分配
- 索引:所属对象、集群分配
- 连接:已配置的外部系统连接
对象定义
使用 references/queries.md 获取物化视图、视图、索引和源的 SQL 定义。这对优化分析至关重要——SQL 定义会告诉你内容的计算方式:
- 连接模式和连接顺序
- 筛选谓词(或缺失的筛选谓词——缺少时间筛选是常见问题)
- 聚合策略
- 物化视图是否重复了本可共享的逻辑
步骤 3:分析 — 性能和资源指标
新鲜度(延迟分析)
查询 mz_internal.mz_materialization_lag,获取各对象的延迟。其 local_lag
和 global_lag 列是普通的 interval,因此可以直接比较和排序;slowest_global_input_id 则指出拖慢该对象的输入。两种延迟都是相对于输入的前沿计算的,而非相对于墙上时钟:如果源已暂停,管道会显示零延迟,但数据可能已经变得任意陈旧,因此还要将 mz_frontiers.write_frontier 与 now() 比较(使用 Write Frontiers 查询)。
write_frontier 不在此关系中,而是位于
mz_internal.mz_frontiers,类型为 mz_timestamp。为便于阅读,可将其转换为 timestamptz;若要获取原始数值,则应先转换为 text,再转换为 bigint,绝不能直接转换为 bigint。查询语句见 references/queries.md。
水合状态
查询 mz_internal.mz_hydration_statuses,检查所有数据流是否都已水合。初始启动后仍未水合的对象可能表明资源压力或配置问题。请对副本列使用 LEFT JOIN:如果没有可供水合的副本,replica_id 为 NULL;使用内连接会隐藏这些对象。
阻碍压缩的暂停集群
用户集群上没有副本的物化视图会阻碍其读取的所有输入进行压缩,导致这些输入的存储持续增长,而 Materialize 不会对此发出提示。每次健康检查都要排查此情况,并在执行摘要中报告任何发现。运行 references/queries.md 中的“无副本集群上的物化视图”查询。要解决此问题,可为集群添加副本,这会立即释放这些输入;如果没人需要该视图,也可以将其删除。托管集群使用 ALTER CLUSTER <name> SET (REPLICATION FACTOR = 1),非托管集群使用 CREATE CLUSTER REPLICA <name>.<replica> (SIZE = '<size>')。无副本集群上的索引以及 SCHEDULE = ON REFRESH 集群不会阻碍其输入进行压缩。
内存和资源消耗
mz_internal.mz_cluster_replica_utilization:获取每个副本进程的内存/CPU 使用率mz_internal.mz_cluster_replica_metrics:获取原始内存指标,每个(副本、进程)对应一行mz_internal.mz_index_advice:识别可优化的物化视图/索引
Worker 偏斜(Worker 之间的 CPU 不均衡)
使用 WITH SKEW 查找某个 Worker 承担了不成比例的 CPU/内存工作量的运算符。
请通过 query 工具运行这些命令,不要使用 query_system_catalog:
EXPLAIN ANALYZE 会在作为 cluster 参数传入的集群上执行;对于对象级命令,该集群必须是物化视图/索引所在的集群。选错集群不一定会报错:在另一个只有一个副本的集群上,或在默认集群只有一个副本时通过 query_system_catalog 执行,对象级命令会返回空结果,看起来像是“没有偏斜”;如果有多个副本,读取会失败,并显示 log source reads must target a replica;如果没有副本,则会显示 has no replicas available to service request。不使用 query,本节就无法实际操作。
集群级(在要检查的集群上运行):
EXPLAIN ANALYZE CLUSTER CPU WITH SKEW
对象级(对物化视图及其索引分别运行):
EXPLAIN ANALYZE CPU WITH SKEW FOR MATERIALIZED VIEW <schema>.<mv_name>
EXPLAIN ANALYZE CPU WITH SKEW FOR INDEX <schema>.<index_name>
如果存在偏斜:先识别发生偏斜的运算符(通常是 TopK/窗口/聚合/连接/去重),然后检查定义(SHOW CREATE ...),并建议具体的 SQL 修改(移除/调整提示、重构键/分区方式,或重写物化视图)。
索引建议
查询 Materialize 内置顾问 mz_internal.mz_index_advice。它会输出且仅输出六种建议:keep、drop unless queried directly、convert to a view、convert to a view with an index、convert to materialized view、add index。按子集筛选会悄然漏掉实际建议;每种建议的含义见 references/queries.md。
成本分析(可选)
使用 references/queries.md 中的成本分析查询(按副本计价)。
撰写建议时,务必量化 credits 的影响(credits 是 Cloud 的计费单位;在自托管环境中,随附规格沿用 Cloud 的数值,而操作员自行定义的规格则采用操作员设定的数值,默认为 0,因此最多只能将其作为相对权重呈现)。
对象依赖关系
查询 mz_internal.mz_object_dependencies 以了解依赖关系图。
第 4 步:报告——生成分析报告
按照 references/report-template.md 生成结构化 Markdown 报告,内容包括:执行摘要、集群拓扑、已部署对象、性能分析(新鲜度、水合度、利用率、工作节点负载偏斜、源和接收器健康状况)、成本分析、索引建议、SQL 层级分析,以及附有具体 SQL 的编号建议。
集群拓扑表应根据 references/queries.md 中的 Cluster Topology 查询以及其中 Current Compute Cost per Cluster 查询的 credits 列生成。
撰写建议
**务必包含具体的 SQL 命令。**例如:
良好:
**建议:**取消物化
my_schema.unused_mv以节省内存。SHOW CREATE MATERIALIZED VIEW my_schema.unused_mv DROP MATERIALIZED VIEW my_schema.unused_mv CREATE VIEW my_schema.unused_mv AS <definition>
不佳:
**建议:**考虑取消物化
my_schema.unused_mv。
故障排除手册
结尾务必提供用于修复问题的具体 SQL 命令,并且未经用户同意,绝不要执行这些命令:扩容或增加副本会产生费用,删除或更改对象会丢失状态。以下所有修复操作都是 DDL,两个工具都会拒绝执行,因此应将这些命令交给用户。
“为什么我的物化视图已过时?”
诊断步骤:
- 先检查 MV 所在集群是否有任何副本:查询
mz_clustersLEFT JOINmz_cluster_replicas(Clusters and Replicas 查询),不要看replication_factor,因为非托管集群中的该值为 NULL,且无法反映未计费副本。没有副本的集群不会运行任何内容,后续步骤也难以奏效。 - 检查
mz_internal.mz_hydration_statuses:MV 是否已完成数据加载?该集群上的其他对象是否也都已完成数据加载(Non-Hydrated Objects 查询,并限定为该集群)? - 检查
mz_internal.mz_cluster_replica_status_history中近期是否有原因是oom-killed的offline事件。这涵盖 cgroup OOM killer、堆内存限制器以及 lgalloc 溢出磁盘已满的情况(Replica Restarts 查询;模拟器不会记录原因,因此应查看offline计数):OOM 循环通常会在当前状态中显示为online,且利用率采样值不高。大多数 OOM 都发生在数据加载期间,因此当步骤 2 显示所有内容都已完成数据加载,且每个进程最新的历史记录行状态为online时,循环就结束了;如果在数据加载完成后仍反复被杀,则属于稳态循环,只有调整大小或减少集群上的负载才能解决。 - 检查
mz_internal.mz_cluster_replica_utilization:memory_percent接近 100 表示 RAM 已满,后续增长会使用 swap(如果有),表现为数据加载缓慢或延迟;memory_percent保持不变而heap_percent(RAM 加 swap,相对于限制值)不断升高,说明正在使用 swap;接近 100 时,下一次峰值就会导致副本被杀。无论哪种情况,都应扩容、迁移 MV,或减少集群承载的内容(参见下方的修复方法和步骤 7)。 - 检查
mz_internal.mz_source_statuses:上游源是否有错误? - 检查
mz_internal.mz_materialization_lag,查看 MV 的延迟(参见 Freshness) - 如果
query工具可用,则在 MV 所在集群上运行EXPLAIN ANALYZE MEMORY FOR MATERIALIZED VIEW <schema>.<mv>,查看各运算符的内存用量,并找出开销较大的结构(大型 arrangement、没有索引的联接、缺少时间过滤器)。
常见修复方法:
如果 MV 所在集群没有副本:
ALTER CLUSTER <cluster_name> SET (REPLICATION FACTOR 1)
-- Unmanaged cluster: add a replica directly
CREATE CLUSTER REPLICA <cluster_name>.r1 (SIZE = '<size>')
如果集群过载(内存/CPU 使用率高):
-- Option A: Scale up the cluster (unmanaged: DROP and CREATE its replicas
-- at the bigger size instead)
ALTER CLUSTER <cluster_name> SET (SIZE = '<next_size_up>')
-- Option B: Move the MV to a different cluster
SHOW CREATE MATERIALIZED VIEW <schema>.<mv_name>
DROP MATERIALIZED VIEW <schema>.<mv_name>
CREATE MATERIALIZED VIEW <schema>.<mv_name> IN CLUSTER <new_cluster> AS <definition>
如果上游源未运行:
SELECT name, status, error, last_status_change_at
FROM mz_internal.mz_source_statuses
WHERE status != 'running'
并非所有非 running 状态都表示故障,只有 stalled 状态带有 error;下方的“我的源是否正常?”会列出每种状态的含义。
请先修复上游源的问题。MV 的新鲜度取决于源的健康状况。
“为什么我的集群内存不足?”
诊断步骤:
- 检查
mz_internal.mz_cluster_replica_utilization中的内存百分比,以及mz_cluster_replica_status_history中的oom-killed事件(Replica Restarts) - 检查
mz_internal.mz_index_advice,查看哪些 MV 可以取消物化 - 检查 MV 定义是否缺少时间过滤器
- 检查是否存在冗余索引
- 如果
query工具可用,则在可疑对象所在集群上运行EXPLAIN ANALYZE MEMORY FOR MATERIALIZED VIEW <schema>.<mv>(或FOR INDEX <name>),查看哪些运算符占用的内存最多——这是确认哪个 arrangement 导致问题最直接的方法。
常见修复方法:
取消不需要物化的 MV 的物化:
SELECT o.name, o.type, sc.name AS schema_name, ia.hint, ia.details
FROM mz_internal.mz_index_advice ia
JOIN mz_catalog.mz_objects o ON ia.object_id = o.id
JOIN mz_catalog.mz_schemas sc ON o.schema_id = sc.id
WHERE ia.hint = 'convert to a view'
convert to a view with an index 和 convert to materialized view 也是内存建议,但对应的修复方法不同,因此在执行此操作前,请阅读完整的建议集(references/queries.md 中的 Index Advice 查询)。
-- For each candidate:
SHOW CREATE MATERIALIZED VIEW <schema>.<mv_name>
DROP MATERIALIZED VIEW <schema>.<mv_name>
CREATE VIEW <schema>.<mv_name> AS <definition>
删除未使用的索引:
SELECT o.name, o.type, sc.name AS schema_name, ia.hint, ia.details
FROM mz_internal.mz_index_advice ia
JOIN mz_catalog.mz_objects o ON ia.object_id = o.id
JOIN mz_catalog.mz_schemas sc ON o.schema_id = sc.id
WHERE ia.hint = 'drop unless queried directly'
-- Verify with the user before dropping
DROP INDEX <schema>.<index_name>
扩容集群(非托管集群:改为删除并创建更大规格的副本):
ALTER CLUSTER <cluster_name> SET (SIZE = '<next_size_up>')
“我的源运行正常吗?/ 我的源是否已完成快照?”
诊断步骤:
- 检查
mz_internal.mz_source_statuses中的源错误 - 检查
mz_internal.mz_source_statistics中的摄取进度 - 检查
mz_internal.mz_materialization_lag中的端到端延迟
常见修复方法:
如果源未运行:
SELECT name, status, error
FROM mz_internal.mz_source_statuses
WHERE status != 'running'
状态为 created(尚无状态记录)、starting、running、paused、stalled 或 dropped;文档还列出了代码不会生成的 failed。只有 stalled 会携带 error。Webhook 和 progress 行始终显示 running。created 和 starting 是暂态,属于正常情况;paused 表示源所在的集群没有副本,再怎么等待也无法解决:
-- paused: give the source's cluster a replica
ALTER CLUSTER <cluster_name> SET (REPLICATION FACTOR 1)
-- unmanaged cluster: CREATE CLUSTER REPLICA <cluster_name>.r1 (SIZE = '<size>')
-- stalled/failed on bad credentials:
ALTER SECRET <secret_name> AS '<new_value>'
如果 snapshot_committed 为 false,表示源仍在加载初始快照。对于大型源,这是正常情况——请等待加载完成;源或副本启动后的约两分钟内,即使计数器为零,它也会显示 false。如果完全没有 mz_source_statistics 行,说明该源从未运行,因此请检查其状态以及所在集群是否有副本,而不是继续等待;已暂停的源会保留过时的行,因此应先查看 status。
“我的环境运行状况如何?”
按顺序运行以下检查:
mz_internal.mz_cluster_replica_statuses— 用户集群的所有副本是否都已就绪,并且mz_cluster_replica_status_history中是否没有近期的oom-killed?- 已暂停的集群 — 用户集群上是否有任何物化视图没有副本?这会阻碍其输入的压缩(暂停的集群阻碍压缩)。
mz_internal.mz_source_statuses— 所有源是否都在运行?mz_internal.mz_sink_statuses— 所有 Sink 是否都在运行?mz_internal.mz_cluster_replica_utilization— 是否存在资源压力?
“如何优化以节省成本?”
- 检查
mz_internal.mz_index_advice,查找可优化项 - 检查集群利用率——集群是否过度配置?
- 检查
mz_catalog.mz_cluster_replica_sizes中的信用点费率
说明
- 访问权限由 RBAC 管理,因此你只能看到凭据有权访问的数据。目录不受相同方式的限制:即使某个角色没有对象授权,也仍能读取完整的对象清单、每个视图和 MV 的
definition,以及全部mz_index_advice。启用 RBAC 时,query和每个未自动路由的读取操作还需要在其运行所在的集群上拥有USAGE权限(mz_catalog_server会将其授予PUBLIC)。是否启用 RBAC 检查取决于部署及其配置;SHOW enable_rbac_checks和SHOW enable_session_rbac_checks可用于查看(任一项为on即表示已启用)。 - 新鲜度数值是某一时刻的快照。请重新运行以检查延迟是保持稳定还是持续增长。