SQL 分区表索引策略与性能提升

7次阅读

SQL 分区表索引策略与性能提升

分区表加索引不是简单“建一个就行”,关键在索引类型、字段选择和分区键是否对齐。用错策略,不仅不提速,还可能让查询更慢、维护更重。

分区键必须是索引键的前导列(本地索引前提)

本地索引(LOCAL)自动按分区对齐,但要求分区键必须包含在索引定义中,且通常需作为最左列。否则 oraclepostgresql 等会拒绝创建,或降级为全局索引。

  • 正确示例(按 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 看膨胀率
text=ZqhQzanResources