物化视图需显式建索引,单列索引对多条件查询效果有限;复合索引按最左前缀原则设计,高选择性列优先;include用于覆盖查询避免回表;brin仅适用于物理有序数据;索引过多会拖慢并发刷新。

为什么物化视图上建了单列索引,EXPLAIN 还是 Seq Scan?
因为物化视图本质是一张只读物理表,它不继承基表索引,也不自动创建任何索引。查询时是否走索引,完全取决于你是否为 WHERE、JOIN 或 ORDER BY 中实际用到的字段组合显式创建了匹配的复合索引。单列索引对 WHERE a = 1 AND b = 2 效果有限,尤其当两列联合选择性远高于单独任一列时。
CREATE INDEX 时列顺序怎么定?
复合索引遵循“最左前缀”原则,顺序直接影响能否命中。关键看查询谓词是否能覆盖索引左侧连续部分:
- 若高频查询是
WHERE region = '华东' AND month >= '2024-01',应建CREATE INDEX idx_mv_region_month ON mv_orders_summary (region, month);把高选择性列(如region)放左边,先快速过滤大块数据 - 若同时有
ORDER BY month DESC, region,且month是时间字段、天然有序,可考虑(month, region)—— 但必须确认该顺序在 WHERE 中也高频出现,否则右侧列可能无法利用 - 避免反向顺序:索引
(month, region)对WHERE region = '华东'单条件无效;而(region, month)对WHERE region = '华东' AND month BETWEEN '2024-01' AND '2024-06'可高效范围扫描
什么时候该加 INCLUDE 而不是扩大索引键?
当你需要避免回表(即仅靠索引就能返回所有字段),又不想让索引键膨胀影响写性能或存储时,INCLUDE 是更轻量的选择:
- 例如查询常为
SELECT month, sum_amount FROM mv_orders_summary WHERE region = '华东',可建CREATE INDEX idx_mv_region_inc ON mv_orders_summary (region) INCLUDE (month, sum_amount) -
INCLUDE列不参与索引排序和搜索逻辑,只存于叶子节点,不增加树高,刷新开销小 - 但注意:
INCLUDE不能用于WHERE条件或ORDER BY—— 它只服务“覆盖查询”,别指望靠它加速过滤或排序
BRIN 索引适合物化视图吗?
仅当物化视图数据天然按某字段物理聚簇(如按时间聚合后插入顺序与 month 或 day 高度一致)时才值得考虑 BRIN:
- 建法:
CREATE INDEX idx_mv_month_brin ON mv_orders_summary USING BRIN (month) - 优势:索引体积极小(通常 KB 级),刷新快,适合亿级行、按天/月分区的汇总视图
- 风险:如果物化视图经多次并发刷新或手动 INSERT 导致物理顺序打散,BRIN 效果会断崖下跌,甚至比全表扫描还慢;此时必须换回 B-tree
- 验证方式:执行
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM mv_orders_summary WHERE month = '2024-03',观察Buffers是否显著低于 B-tree 同类查询
复合索引不是堆得越多越好。每个索引都会拖慢 REFRESH MATERIALIZED VIEW CONCURRENTLY 的速度,尤其当物化视图本身超大、且索引列含非空约束或表达式时——这些细节容易被忽略,但直接影响刷新稳定性与查询延迟的平衡。










