CREATE TABLE ... CLUSTER PRIMARY KEY)。PK_WITH_CLUSTER=1 时,主键自动转为聚集索引。CREATE TABLE t1 (id INT, content CLOB)
STORAGE(LOB ON lob_ts); -- LOB存储在lob_ts表空间
ALTER TABLE t1 MOVE LOB ON new_lob_ts; -- 迁移LOB列到新表空间
| 特性 | 堆表 | B树表 | 分区表 |
|---|---|---|---|
| 存储结构 | 扁平B树+物理ROWID | B+树+逻辑ROWID | 子表(堆表/B树表)+分区键 |
| 插入性能 | ⭐⭐⭐⭐(高并发) | ⭐⭐(需维护索引有序) | 依赖子表类型 |
| 范围查询效率 | ⭐(需全扫描) | ⭐⭐⭐⭐(有序访问) | 依赖分区剪枝+子表类型 |
| LOB分离存储 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 |
| 适用场景 | 高频插入日志类表 | 事务处理表(OLTP) | 海量数据表、历史数据管理 |
首先需要设置同一种表结构,设置id、name、create_time、grade、city不同列,不同的表对象通过STORAGE()来修改。
id INT PRIMARY KEY, name VARCHAR(50), create_time DATETIME, grade INT, city VARCHAR(20)
对于不同的表来说使用level来按照id对于每个表循环插入100万条数据。
INSERT INTO table_name (id, name, create_time, grade, city)
SELECT
LEVEL AS id,
'User_' || LEVEL AS name,
SYSDATE - MOD(LEVEL, 365) AS create_time, -- 随机日期
MOD(LEVEL, 100) AS grade, -- 成绩0-99
DECODE(MOD(LEVEL, 4), 0,'北京', 1,'上海', 2,'广州', 3,'深圳') AS city
FROM DUAL
CONNECT BY LEVEL <= 1000000; -- 生成10万行[1,6](@ref)
对B树表、堆表在插入100万行数据时的性能监控报告横向对比分析。基于SQL Monitoring Report数据,结合存储结构特性,以下是关键性能指标对比表:
| 指标 | B树表 | 堆表 |
|---|---|---|
| 总耗时 | 9.55s | 6.96s |
| INSERT2 | 82.11% (7.84s) | 75.39% (5.24s) |
| 逻辑读(页) | 3,082,811 | 2,992,861 |
| 物理读(页) | 1,000,000 | 1,000,000 |
| 数据生成耗时 | 1.44s (15.11%) | 1.45s (20.84%) |
| 执行次数 | 3,336次 | 3,336次 |
INSERT2操作耗时差异
| 存储结构 | 数据组织方式 | 写入特点 | 适用场景 |
|---|---|---|---|
| B树表 | 主键有序存储(索引组织表) | 需维护B+树结构,页分裂代价高 | 高频率按主键查询的场景 |
| 堆表 | 无序存储(堆组织表) | 插入快,但查询需额外索引支持 | 频繁插入且较少范围查询的场景 |
对于不同的表都使用同一句sql查询,查询id=500000的情况
SELECT * FROM table_name WHERE id = 500000;
| 性能指标 | B树表 | 堆表 |
|---|---|---|
| 总耗时 | 0.286ms | 0.148ms |
| 逻辑读(页) | 3 | 4 |
| 物理读(页) | 0 | 0 |
| 执行计划关键操作 | CSEK2(索引扫描) |
SSEK2+BLKUP2(索引扫描+回表) |
| 扫描行数 | 1 | 1 |
| 耗时最高操作 | CSEK2 0.2101ms |
NSET2 0.0548ms |
CSEK2(唯一索引扫描)SSEK2(索引扫描)→ BLKUP2(回表)CSCN2(全表扫描)city或create_time,查询id=500000无法触发分区裁剪,需扫描所有分区。id创建全局索引,优化器退化为全表扫描PLL操作耗时0.000044s)。| 结构特性 | B树表 | 堆表 |
|---|---|---|
| 数据物理组织 | 主键有序存储 | 无序堆存储 |
| 主键查询路径 | 索引树直达数据 | 索引→ROWID→数据页 |
| 非分区键查询代价 | 低(索引高效) | 中(需回表) |
| 适用场景 | 高频主键查询 | 写密集型+随机写入 |
| 特性 | 堆表(Heap-Organized) | 索引组织表(IOT) |
|---|---|---|
| 分区策略支持 | 全部(Range/List/Hash/复合分区) | 仅基础分区(Range/List/Hash) |
| 分区键与主键关系 | 无需关联 | 分区键必须是主键的子集 |
| 组合分区支持 | ✅ Range-Hash,Range-List等 | ✅ 支持Range-Hash,List-Range |
| 数据物理存储 | 无序堆 | 按主键有序的B树结构 |
| 典型适用场景 | 写密集型、无顺序要求 | 读密集型、强主键查询场景 |
| 比较指标 | 分区堆表 (partitioned_heap) | 分区B树表 (partitioned_iot) | 差异/分析 |
|---|---|---|---|
| 表类型 | 堆表 | B树表(索引组织表) | B树表需维护索引结构,增加开销。 |
| SQL ID | 553 | 562 | - |
| 执行持续时间 | 2.484秒 | 9.975秒 | 堆表快4.01倍:B树表索引维护导致延迟。 |
| 受影响行数 | 1,000,000 | 1,000,000 | 相同。 |
| 物理读 (页) | 1,000,000 | 1,000,000 | 相同:数据生成阶段(CONNECT BY)类似。 |
| 逻辑读 (页) | 253,413 | 2,994,505 | B树表高11.8倍:索引节点访问频繁(B树表需维护排序和分区索引)。 |
| INSERT操作时间 | 0.7409s | 8.2543s | B树表高11.14倍:INSERT在B树表中是主要瓶颈(索引维护)。 |
| 投影操作时间(PRJT2) | 1.4759s | 1.455s | 两者的投影操作时间相近(因为DECODE(MOD(LEVEL,4)))操作相同。 |
| 数据生成效率 | 0.0032s | 0.0039s | 在100万条的数据插入里面两者的数据生成效率相近。 |
| 主要瓶颈 | 投影计算(PRJT2) | INSERT操作 | B树表索引维护使其不适合高频插入;堆表更适合批量写入。 |
APPEND提示使用了直接路径插入(Direct Path Insert),减少了空间分配开销。CONNECT BY生成数据),但操作权重不同:以下场景是在非分区键查询场景下:
| 指标 | 分区IOT表 (partitioned_iot) |
分区堆表 (partitioned_heap) |
差异原因分析 |
|---|---|---|---|
| 逻辑读(Logical Read) | 12页 | 10页 | IOT表需额外访问主键索引结构,增加逻辑读。 |
| 实际扫描行数 | 1500行 → 返回96行 | 1200行 → 返回74行 | IOT表数据存储更分散,需扫描更多行才能满足grade>90条件。 |
| 执行时间(Duration) | 0.516ms | 0.395ms | IOT表额外索引访问和分散存储导致耗时略高。 |
| CSCN2操作 | 0.3045ms | 0.2113ms | IOT表扫描阶段消耗更多资源。 |
| 过滤效率 | 1500行输入 → 96行输出 (6.4%) | 1200行输入 → 74行输出 (6.2%) | 两者过滤效率接近,但IOT需扫描更多数据。 |
CSCN2扫描索引结构(INDEX33555506),需访问更多逻辑页定位数据。CSCN2直接顺序扫描物理数据页(INDEX33555496),逻辑读更少。grade是非分区键,高分数据分散存储(如主键1和主键10000的grade>90记录可能位于不同索引页),导致扫描更多行。CSCN2操作耗时0.3045ms(堆表为0.2113ms),说明IOT的索引扫描成本更高。PARALLEL并行扫描,但IOT表并行执行效率更低(PLL操作占比7.49% vs 堆表9.03%),因并行任务需协调分散的索引结构。DBMS_STATS.GATHER_TABLE_STATS 。文章
阅读量
获赞
