【Oracle专栏】全局 && 本地复合索引 实验

Oracle && OceanBase 相关文档,希望互相学习,共同进步

风123456789~-CSDN博客


1.背景

生产由于频繁查某个大表,优化时需要给字段增加索引,根据实际业务场景,发现大表的使用中频繁需要查询某几个字段,于是把这几个字段建立复合索引,方便索引命中。另外,本文还对比了 全局复合索引、本地复合索引的利弊,分析了 复合索引和分区字段的共用的情况。

欢迎各位同行一起探讨,共同学习。上节增加单列索引:

【Oracle专栏】千万数据表增加索引会影响插入吗https://blog.csdn.net/weixin_42081167/article/details/164849971

2. 实验

2.1 测试环境数据大小

sql 复制代码
select /*+parallel(5)*/count(*) from FM_RPT_KMYEB t; 
--生产 2.7亿   271268263
--测试  873万    8737767

select sum(t.bytes)/1024/1024/1024 from user_segments t
where t.segment_name='FM_RPT_KMYEB'  
--生产  35.16G
--测试   1.44G

表数据上百万,生产上亿。表分区字段为 DATE_ID

sql 复制代码
 select * from FM_RPT_KMYEB T  
 WHERE T.BANK_CODE = '014007029100004001'  AND T.BOOK_ID = 'ff8080819391477b0193aad6673c0959' 
  --AND T.DATE_ID BETWEEN  '2022-01'  AND  '2022-02' 
   AND T.DATE_ID >=  '2022-01'  and T.DATE_ID <='2022-02'

sql执行计划:

2.2 实验 复合索引

上节增加bank_code 的索引,虽然命中了,但还是可以 进一步优化。上节内容如下:

【Oracle专栏】千万数据表增加索引会影响插入吗https://blog.csdn.net/weixin_42081167/article/details/164849971

1 实验思路

根据业务情况,发现还可以升级为复合分区索引,把 BANK_CODEBOOK_IDDATE_ID 组合起来,实现完全免回表的覆盖查询,性能还能再提升一个量级,彻底消除全分区扫描的可能性。

  • 规划索引列顺序 ‌:严格遵循「等值查询列在前,范围查询列在后」原则,本场景下推荐为BANK_CODEBOOK_IDDATE_ID,完全匹配现有查询的过滤逻辑。
  • 提前检查存储空间‌:确认索引所在表空间剩余容量≥表数据量的1/3,避免创建过程中空间不足报错。

1)使用ONLINE在线语法避免阻塞业务写入,搭配NOLOGGING减少大表场景下的重做日志开销,同时开启并行加速创建

sql 复制代码
CREATE INDEX IDX_FM_RPT_KMYEB_COMP 
ON FM_RPT_KMYEB (BANK_CODE, BOOK_ID, DATE_ID)
LOCAL  -- 声明为本地分区索引,自动与表分区一一绑定
TABLESPACE IDX_TBS  -- 指定独立的索引表空间,提升IO性能
ONLINE  -- 在线创建,不阻塞业务插入更新
PARALLEL 8  -- 开启8并行度,大幅压缩大表创建耗时
NOLOGGING  -- 关闭重做日志,减少磁盘IO压力
COMPRESS 2; -- 启用键压缩,减少重复索引值的存储空间

2)创建完成后必须将索引并行度改回默认值,避免后续业务查询被意外强制走并行执行,消耗过多系统资源

sql 复制代码
ALTER INDEX IDX_FM_RPT_KMYEB_COMP NOPARALLEL;
ALTER INDEX IDX_FM_RPT_KMYEB_COMP LOGGING;

注意:

  • ❌ 不要将分区键放在复合索引的前导列,否则会破坏最左前缀匹配规则,导致等值查询条件无法命中索引。
  • ❌ 禁止在创建过程中对表执行DDL操作,避免出现索引分区状态异常。
  • ✅ 对于按日期分区的大表,后续执行DROP PARTITION等维护操作时,Oracle会自动同步清理对应索引分区,无需手动重建全量索引。

2.相关问题

1)是否需要删除原有的单列索引?

新建的(BANK_CODE, BOOK_ID, DATE_ID)复合分区索引已经完全覆盖了原单列BANK_CODE索引的所有查询能力,保留单列索引属于冗余设计,推荐直接删除。

✅ 保留单列索引的弊端

  • 额外空间占用 ‌:单列索引会额外占用磁盘存储空间,对于2.7亿行的大表,单列索引本身可能占用数GB空间,和复合索引形成双重存储浪费。

  • DML性能损耗 ‌:每次执行INSERT/UPDATE/DELETE操作时,Oracle需要同时维护两个索引的B树结构,写入开销直接翻倍,高并发场景下会明显拖慢写入性能。

  • 优化器选择混乱 ‌:当两个索引都能匹配查询条件时,CBO优化器可能生成错误的执行计划,出现本该走复合索引却误选单列索引的情况,导致查询性能波动。

📋 唯一需要保留单列索引的特殊场景:

  • 存在大量仅使用BANK_CODE单个字段作为过滤条件的高频查询,且这些查询无法被复合索引的前导列完全覆盖。本场景中复合索引前导列就是BANK_CODE,天然兼容单列等值查询
2)date_id 已是分区索引了,还需要在复合索引中吗?

DATE_ID作为分区字段,即使本身已经是分区索引,DATE_ID加入复合索引不会产生冗余存储,反而能替代单独的DATE_ID分区索引,减少索引总数,降低DML操作的写入维护开销。能带来显著性能收益,并非冗余设计。

DATE_ID不能放在复合索引的前导列,必须放在等值查询字段BANK_CODEBOOK_ID之后,否则会破坏最左前缀匹配规则,导致等值查询条件无法高效命中索引,反而降低查询性能。

  • 强化分区裁剪能力 ‌:本地复合分区索引的分区结构和表分区严格一对一绑定,把DATE_ID加入索引后,查询可以直接在索引层面完成分区裁剪,无需先回表判断分区范围,进一步减少不必要的IO开销。
  • 适配唯一索引强制约束 ‌:如果后续要在BANK_CODE + BOOK_ID上创建本地唯一索引,Oracle强制要求必须包含分区键DATE_ID,否则会直接抛出ORA-14038错误,无法创建局部唯一索引。
  • 实现完全覆盖查询 ‌:当DATE_ID作为索引列的一部分时,查询的所有过滤条件都能在索引中完成判断,无需回表读取表数据,把IO开销降到最低。

3. 创建复合索引

sql 复制代码
CREATE INDEX IDX_FM_RPT_KMYEB_COMP ON FM_RPT_KMYEB (BANK_CODE, BOOK_ID, DATE_ID)
ONLINE PARALLEL 8 NOLOGGING COMPRESS 2; -- 启用键压缩,减少重复索引值的存储空间

执行:800多万1.44G 用时22秒

sql 复制代码
ALTER INDEX IDX_FM_RPT_KMYEB_COMP NOPARALLEL;
ALTER INDEX IDX_FM_RPT_KMYEB_COMP LOGGING;

---删除单列索引
drop index idx_FM_RPT_KMYEB_bank;

sql执行计划比较:全局复合索引

4. 改为本地复合索引

sql 复制代码
--全局复合分区
drop index IDX_FM_RPT_KMYEB_COMP;
CREATE INDEX IDX_FM_RPT_KMYEB_COMP ON FM_RPT_KMYEB (BANK_CODE, BOOK_ID, DATE_ID)
ONLINE PARALLEL 8 NOLOGGING COMPRESS 2; -- 启用键压缩,减少重复索引值的存储空间

ALTER INDEX IDX_FM_RPT_KMYEB_COMP NOPARALLEL;
ALTER INDEX IDX_FM_RPT_KMYEB_COMP LOGGING;

 
--本地复合分区
drop index IDX_FM_RPT_KMYEB_COMP1;
CREATE INDEX IDX_FM_RPT_KMYEB_COMP1 ON FM_RPT_KMYEB (BANK_CODE, BOOK_ID, DATE_ID) local
ONLINE PARALLEL 8 NOLOGGING COMPRESS 2; -- 启用键压缩,减少重复索引值的存储空间

ALTER INDEX IDX_FM_RPT_KMYEB_COMP1 NOPARALLEL;
ALTER INDEX IDX_FM_RPT_KMYEB_COMP1 LOGGING;

sql执行计划比较:本地复合索引

5.全局复合索引 貌似比本地复合索引 性能下降了?

从两张执行计划的实测数据来看,并不是本地索引性能下降,反而是全局复合索引的执行成本更高,本地复合索引的实际表现更适配分区大表场景。

索引类型 执行成本 核心访问逻辑 实际IO开销
全局复合索引 5 直接走全局索引范围扫描后回表 要遍历整棵全局B树,跨所有分区查找目标行
本地复合索引 6 先做分区裁剪,再走本地索引范围扫描后回表 先跳过所有无关分区,仅在目标分区内扫描索引

🔍看似"成本略高"的真实原因

  • 执行计划里的成本值差异极小,几乎可以忽略不计,本地索引多出来的1点成本,是Oracle执行分区裁剪的极小计算开销,完全不会影响实际查询速度。

  • 本地索引的 PARTITION LIST ITERATOR 操作,代表优化器已经自动识别到了 DATE_ID的范围条件,直接跳过2022-01和2022-02之外的所有历史分区,避免了扫描全量索引数据。

  • 全局索引没有分区裁剪能力,哪怕只查两个月的数据,也要扫描整棵全局索引的所有分支块,在数据量持续增长的场景下,后续性能会越来越差。

✅ 本地索引的长期性能优势

  • 随着表数据量持续增长,本地索引的性能会保持稳定,因为每次查询只需要访问极小范围的分区索引段,不会随着总数据量膨胀而变慢。

  • 高并发写入场景下,本地索引的每个分区独立维护,不会出现全局索引所有DML操作争抢同一棵B树根块的锁竞争问题,写入性能更稳定。

  • 后续清理历史分区时,本地索引会自动同步清理对应索引分区,不会出现全局索引直接失效需要全量重建的问题,运维成本极低。

3.知识点 🎯

1)维度对比

对比维度 全局复合索引 本地分区复合索引
分区维护影响 执行DROP/TRUNCATE分区操作时,索引会直接变为UNUSABLE,必须手动全量重建,亿级表重建可能耗时数小时 分区维护操作自动同步对应索引分区,完全不会影响其他索引分区,无需人工干预
分区裁剪能力 不支持分区裁剪,哪怕只查单个分区数据,也需要扫描整棵全局索引B树 天然支持分区裁剪,查询含分区键时直接定位到对应索引分区,跳过所有无关分区,IO开销仅为全局索引的几十分之一
写入性能 所有DML操作都争抢同一棵全局索引的根块,高并发场景下容易出现锁竞争,成为写入瓶颈 每个分区的索引独立存储,DML操作仅影响当前分区的索引段,写入压力天然分散,性能更稳定
唯一约束支持 可以直接建立跨分区的全局唯一约束,无需包含分区键 只能保证单分区内唯一,要实现全局唯一必须把分区键加入索引列中

两者的核心差异集中在分区绑定关系、运维成本和性能适配场景上,完全适配当前的亿级分区大表优化需求。

2)核心结构差异

  • 全局复合索引 ‌:是一个完整的单棵B树结构,跨表所有分区独立存在,索引分区规则和表分区规则完全解耦,索引分区数量和表分区数量没有必然关联。
  • 本地分区复合索引 ‌:索引分区和表分区严格一一对应,索引分区键必须和表分区键保持一致,新增/删除表分区时,索引分区数量会自动同步变化,无需人工干预。

3)适配场景差异

  • 全局复合索引适用场景 ‌:高并发OLTP系统中,频繁按非分区业务唯一键做单点查询,且分区维护操作频率极低,可接受短时间的索引重建窗口。
  • 本地分区复合索引适用场景 ‌:像当前的按日期分区的亿级大表,高频查询都包含分区键,需要频繁按时间归档清理历史分区,追求7×24小时业务不中断,是数据仓库和海量分析场景的最优选择。

放松一下,加个知识点 😊:

OLTP (全称 Online Transaction Processing),中文叫联机事务处理,是处理日常业务交易记录的数据库技术‌。简单说就是每天用的那些"点一下就生效"的操作,比如银行转账、电商下单、超市收银,都靠 OLTP 系统在背后撑着。

核心特点:

  1. 高并发处理能力‌:能同时支撑大量用户操作,像银行网点同时办理业务的客户,或者电商大促时瞬间涌入的下单请求。
  2. 数据实时性‌:每一笔操作都要立即生效,实时更新到数据库中,用户不能等。
  3. 事务完整性‌:保证每一笔交易都准确无误地完成,要么都成要么都不成,即ACID 特性
    OLAP (联机分析处理)OLTP (联机事务处理) 区别:

1)OLTP 是数据的"源头",主攻"业务执行",核心是事务处理,常用"多维模型"或"数据立方体",更新频率极高,每发生一笔业务就要执行更新。 数据实时性是其关键要求。**处理的数据量相对较小(主要是当前活跃的业务数据)。**用户进行操作(比如点击提交订单),系统必须在秒级甚至毫秒级内响应,否则用户体验会非常差,甚至导致交易失败或业务中断。企业的日常运作,每时每刻都在通过OLTP系统产生最原始的业务数据。

  • OLTP系统: 最看重高并发处理能力低延迟。系统设计必须能随着业务增长方便地扩展以支撑更多用户和交易量。

2)OLAP 是数据的"分析平台",主攻"分析决策",核心是多维分析,主要用"关系数据库",更新频率低,主要是历史数据的快照,定期 从OLTP系统抽取数据进行更新,分析时数据相对静态。处理的数据量通常很大。 **对响应时间容忍度较高。**一个复杂分析查询运行几分钟甚至更长时间,只要能得出有价值的分析结果用于决策,通常是可以接受的。它定期从OLTP系统获取数据,经过清洗、转换、整合(这个过程叫ETL)后,存储到专门为分析优化的结构(如数据仓库)中,用于分析决策。

  • OLAP系统: 最看重复杂查询的执行效率存储容量与扩展性。架构设计要考虑数据量的持续增长。

没有OLTP持续产生准确的数据,OLAP就没有分析的基础;没有OLAP的深度分析,OLTP产生的数据价值就难以充分释放。

今天就到这里吧,ok


项目管理--相关知识

项目管理-项目绩效域1/2-CSDN博客

项目管理-项目绩效域1/2_八大绩效域和十大管理有什么联系-CSDN博客

项目管理-项目绩效域2/2_绩效域 团不策划-CSDN博客

高项-案例分析万能答案(作业分享)-CSDN博客

项目管理-计算题公式【复习】_项目管理进度计算题公式:乐观-CSDN博客

项目管理-配置管理与变更-CSDN博客

项目管理-项目管理科学基础-CSDN博客

项目管理-高级项目管理-CSDN博客

项目管理-相关知识(组织通用治理、组织通用管理、法律法规与标准规范)-CSDN博客


Oracle其他文档,希望互相学习,共同进步

Oracle-找回误删的表数据(LogMiner 挖掘日志)_oracle日志挖掘恢复数据-CSDN博客

oracle 跟踪文件--审计日志_oracle审计日志-CSDN博客

ORA-12899报错,遇到数据表某字段长度奇怪现象:"Oracle字符型,长度50"但length查却没有50_varchar(50) oracle 超出截断-CSDN博客

EXP-00091: Exporting questionable statistics.解决方案-CSDN博客

Oracle 更换监听端口-CSDN博客

相关推荐
SelectDB1 小时前
Doris 直查 Paimon 索引:快手湖上向量检索的共建与落地
大数据·数据库·数据分析
1314lay_10071 小时前
通过Sql Server创建EXCEL文件:master..xp_cmdshell
数据库·excel
zzzll11112 小时前
用 DeepSeek Harness 手搓一个自己的 Agent
数据库
名字还没想好☜2 小时前
Spring @EventListener 事件驱动解耦实战:同步转异步、事务绑定与顺序控制
java·数据库·后端·python·spring
del2 小时前
第十周技术博客
数据库
1314lay_10072 小时前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#
anxiao_m3 小时前
2026大文件传输软件推荐,从速度安全多维度客观测评
数据库·文件传输·传输
IT大白鼠3 小时前
MySQL 分布式集群系列 · 第七篇——生产调优实战:NDB 性能、内存、高可用全方位优化
数据库·分布式·mysql
IvorySQL3 小时前
打造下一代 AI Agent 的统一多模智能数据底座——PostgreSQL 与 AI 的融合演进
数据库·人工智能·postgresql