
分区表加索引不是简单“建一个就行”,关键在索引类型、字段选择和分区键是否对齐。用错策略,不仅不提速,还可能让查询更慢、维护更重。
分区键必须是索引键的前导列(本地索引前提)
本地索引(LOCAL)自动按分区对齐,但要求分区键必须包含在索引定义中,且通常需作为最左列。否则 oracle 或 postgresql 等会拒绝创建,或降级为全局索引。
- 正确示例(按 order_date 分区,索引含该列):
CREATE INDEX idx_orders_local ON orders(order_date, customer_id) LOCAL; - 错误示例(缺失分区键):
CREATE INDEX idx_orders_bad ON orders(customer_id) LOCAL; → 可能报错或无法裁剪分区
高频过滤字段优先入索引,但避免过度冗余
用户常查 customer_id + status,又按 order_date 分区,那组合索引 (order_date, customer_id, status) 比单列索引高效得多——既能分区裁剪,又能快速定位行。
- 若查询多为 WHERE order_date = ? AND customer_id = ?,这个三列索引可全走索引查找
- 若再加 create_time 排序,可扩展为 (order_date, customer_id, status, create_time),避免回表+排序
- 但别把所有 WHERE 字段都塞进去:列越多,索引越重,DML 越慢,空间占用越高
全局索引慎用:强依赖唯一性,但维护成本高
只有需要跨分区唯一约束(如主键/唯一键不包含分区键)时,才考虑 GLOBAL 索引。它不绑定分区,更新分区(如 DROP PARTITION)会令索引失效,必须 REBUILD。
- 典型场景:订单号(order_no)全局唯一,但表按时间分区 → 可建 GLOBAL UNIQUE INDEX idx_order_no ON orders(order_no);
- 风险点:执行 ALTER table … DROP PARTITION 后,该索引状态变为 UNUSABLE,应用查询直接报错
- 替代思路:用带分区键的联合唯一约束(如 (order_no, order_date)),配合本地索引,更稳定
定期检查索引使用率与碎片,别只建不看
分区表数据持续写入,旧分区可能长期只读,对应本地索引却仍在被统计或维护。不清理,统计信息过期;不合并,叶块碎片升高。
- 查哪些索引几乎没被用:
select index_name, used FROM v$object_usage WHERE used = ‘NO’;(Oracle) - 对只读老分区,可将对应索引分区设为 UNUSABLE 后重建,或标记为 READ ONLY 表空间减少维护开销
- PG 中可用 pg_stat_all_indexes 查 idx_scan,结合 pg_total_relation_size 看膨胀率