4、分区索引优化:本地索引 vs 全局索引、索引维护策略、索引对加载的影响
索引这东西,在分区表里玩不好,加载时间直接翻倍。我见过太多人把普通表的索引习惯直接搬过来,结果分区表一跑,全乱套了。
今天咱们就聊聊分区索引的核心选择——本地索引和全局索引,到底什么时候该用哪个,以及怎么维护才能不让索引拖累加载速度。
4.1 本地索引 vs 全局索引:核心差异
先搞清楚定义。本地索引,就是每个分区独立维护自己的索引结构。全局索引,是整个表共享一套索引。
听起来简单,但实际影响很大。我画了张图,帮你快速理解两者的结构差异。
你看,本地索引是跟着分区走的。每个分区有自己的索引树,互不干扰。全局索引则是一棵大树,覆盖所有分区。
那实际用起来有什么区别?我整理了个对比表,一目了然。
| 对比维度 | 本地索引 | 全局索引 |
|---|---|---|
| 索引结构 | 每个分区独立 | 全表共享一棵树 |
| 分区修剪 | 天然支持,只扫相关分区 | 不支持,可能扫全表索引 |
| 分区交换 | 不影响,索引随分区走 | 必须重建或标记不可用 |
| 唯一约束 | 只能保证分区内唯一 | 保证全局唯一 |
| 查询性能 | 分区修剪后很快 | 跨分区查询可能更快 |
| 维护成本 | 低,分区操作不影响 | 高,分区操作后需重建 |
4.2 索引对加载的影响
说到加载时间,索引是双刃剑。用好了加速,用不好拖死。
我遇到过一件事。有个系统每天加载历史数据,用了全局索引。每次加载完新分区,索引就得重建。重建一次半小时,用户直接炸了。
后来改成本地索引,加载完新分区直接 attach 上去,索引自动可用。加载时间从 40 分钟降到 5 分钟。
为什么会这样?因为全局索引在分区操作后,必须做 ALTER INDEX ... REBUILD。这个操作要扫描全表数据,重新构建整棵 B+ 树。数据量越大,重建越慢。
本地索引就没这个问题。你想想看,每个分区独立,新分区 attach 上来,它的索引已经建好了。旧分区 detach 走,索引也跟着走。完全不需要重建。
核心原则:如果加载场景涉及频繁的分区交换、truncate、drop 操作,优先选本地索引。全局索引在这些场景下会成为性能瓶颈。
4.3 索引维护策略
索引不是建完就不管了。维护不好,碎片多了,加载一样慢。
我个人的习惯是,按场景分策略维护。
4.3.1 本地索引维护
本地索引的维护相对简单。因为每个分区独立,你可以只维护活跃分区。
- 定期重建:对频繁写入的分区,每周或每月重建一次索引
- 按需重建:加载大量数据后,只重建受影响的分区
- 监控碎片率:碎片率超过 30% 时触发重建
举个例子,假设你按天分区,只保留最近 30 天数据。那只需要重建最近几天的分区索引,历史分区基本不动。
-- 只重建特定分区的本地索引
ALTER INDEX idx_order_date
REBUILD PARTITION p_20240101;
-- 或者重建所有分区
ALTER INDEX idx_order_date REBUILD;
4.3.2 全局索引维护
全局索引的维护就麻烦多了。每次分区操作后,索引可能变成 UNUSABLE 状态。
注意:全局索引变成 UNUSABLE 后,查询会全表扫描。如果不及时重建,加载时间会暴增。我曾经见过一个系统,全局索引失效后没发现,查询从 2 秒变成 2 分钟。
维护策略有几种:
- 立即重建:分区操作后立刻重建,保证查询性能
- 延迟重建:允许短暂不可用,在低峰期重建
- 在线重建:使用
ONLINE选项,减少锁影响
-- 重建全局索引(会锁表)
ALTER INDEX idx_global_user_id REBUILD;
-- 在线重建(减少锁影响)
ALTER INDEX idx_global_user_id REBUILD ONLINE;
-- 重建所有不可用索引
ALTER INDEX ALL REBUILD;
4.4 如何选择:本地还是全局?
这个问题没有标准答案。我根据经验总结了一套选择逻辑。
| 场景 | 推荐索引类型 | 原因 |
|---|---|---|
| 频繁分区交换(加载场景) | 本地索引 | 避免重建开销,加载更快 |
| 需要全局唯一约束 | 全局索引 | 本地索引无法保证全局唯一 |
| 查询经常跨分区 | 全局索引 | 避免多次索引扫描 |
| 按分区键查询为主 | 本地索引 | 分区修剪后性能很好 |
| 历史数据归档 | 本地索引 | 分区 detach 不影响索引 |
| OLTP 高并发写入 | 本地索引 | 减少索引争用 |
我的建议:如果拿不准,默认用本地索引。大多数分区表场景,本地索引都够用。只有明确需要全局唯一约束或跨分区高性能查询时,才考虑全局索引。
4.5 避坑指南
最后分享几个我踩过的坑。
坑一:全局索引重建时机
我曾经在加载高峰期重建全局索引,结果锁表锁了 10 分钟,业务直接停了。后来改成 REBUILD ONLINE,但 ONLINE 也有代价——它会占用更多资源,加载速度会变慢。
坑二:本地索引的分区键选择
本地索引如果不包含分区键,分区修剪可能失效。你想想看,索引里没有分区信息,数据库怎么知道该扫哪个分区?所以本地索引最好把分区键放在前面。
-- 好的本地索引(包含分区键)
CREATE INDEX idx_order_date_local
ON orders(order_date, user_id) LOCAL;
-- 不好的本地索引(没有分区键)
CREATE INDEX idx_user_id_local
ON orders(user_id) LOCAL;
坑三:索引碎片监控
我见过一个系统,索引碎片到了 70% 还没人管。加载时间从 10 分钟涨到 40 分钟。后来加了监控,碎片超过 30% 自动告警,问题就解决了。
嗯,索引这块就聊这么多。记住一句话:加载场景优先本地索引,维护策略要跟上,碎片监控不能少。做到这三点,索引就不会成为加载的瓶颈。