把表“塞进”内存——IM 列存储

在传统行式存储中,即使只查询其中几列,Oracle 也必须把整行读进 Buffer Cache。对于分析型 SQL(大量列但仅扫少数几行),这种“拖泥带水”的方式既浪费内存带宽又拉高 CPU。 Oracle 12.1.0.2 引入 In-Memory Column Store(IM 列存储),以列为单位、纯内存、压缩、向量化扫描,专为 OLAP / 混合负载 打造。


架构速览:IM 列存储在 SGA 中的位置

区域说明
Buffer Cache传统行式缓存,事务依旧在此发生
Shared Pool保存列存储字典、表达式统计信息等
In-Memory Area(新 SGA 子池)INMEMORY_SIZE 初始化参数设定大小,存放列式副本

列副本是 只读 的,DML 仍走 Buffer Cache → 后台进程定期把更新合并到 IM 区。


优化器如何决定“要不要走列存储”

优化器成本模型在 12c 被增强,会自动识别:

  • 表/分区是否 INMEMORY
  • 当前会话是否允许 IM 扫描(INMEMORY_QUERY
  • 统计信息是否“IM 感知”(OPTIMIZER_INMEMORY_AWARE = TRUE

一句话:谁的成本低就选谁。IM 扫描在单列过滤、聚合场景下成本通常远低于行式全表扫 + 磁盘 I/O。


三把“开关”控制 IM 查询

初始化参数作用域典型用法
INMEMORY_QUERYSESSION / SYSTEM彻底关闭 IM 扫描(测试回退方案)
OPTIMIZER_INMEMORY_AWARESYSTEM设为 FALSE 时优化器假装看不到 IM 属性
OPTIMIZER_FEATURES_ENABLESYSTEM若 < 12.1.0.2,等价于 OPTIMIZER_INMEMORY_AWARE=FALSE

SQL 级 也可使用 Hint 做细粒度控制: /*+ INMEMORY */ 强制尝试 IM 扫描;/*+ NO_INMEMORY */ 显式屏蔽。


动手实验:30 秒跑一次“内存中表扫描”

准备环境

-- 1. 给表加 In-Memory 属性(HIGH 压缩)
ALTER TABLE oe.product_information INMEMORY MEMCOMPRESS FOR QUERY HIGH;

-- 2. 手动触发一次填充(也可等待首次查询)
EXEC DBMS_INMEMORY.REPOPULATE('OE','PRODUCT_INFORMATION');

执行查询

SELECT *
FROM   oe.product_information
WHERE list_price > 10
ORDER  BY product_id;

查看执行计划

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

输出关键片段:

--------------------------------------------------------------------------------------------
|Id| Operation                   | Name               |Rows|Bytes |TempSpc|Cost(%CPU)|Time|
--------------------------------------------------------------------------------------------
|*2|   TABLE ACCESS INMEMORY FULL| PRODUCT_INFORMATION | 285| 62415|     | 5   (0)|00:00:01|
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
  2 - inmemory("LIST_PRICE">10)
      filter("LIST_PRICE">10)
  • INMEMORY FULL 证明走了 IM 列存储;
  • inmemory(...) 表示列式谓词评估;
  • Cost 从 21 降到 5,扫描时间 < 1 秒。

常见问题

  1. Hint 无效? 确认对象已 INMEMORY,并检查 INMEMORY_QUERY = ENABLE
  2. 为什么还是走全表扫? 可能是列存储尚未填充完,查 V$IM_SEGMENTS.POPULATE_STATUS
  3. DML 会变慢吗? IM 区只读,DML 仍走 Buffer Cache;大量更新时需关注后台 IMCO 合并负载。
  4. 列太多内存不够? 可以只把热列设为 INMEMORYALTER TABLE t INMEMORY (col1, col2) NO INMEMORY (col3);
  • IM 列存储 = 内存 + 列式 + 压缩 + 向量化扫描
  • 优化器基于成本自动决策,亦可 Hint 强制/禁用
  • 通过 INMEMORY_* 参数与 Hint 就能完成灰度测试或性能回退
  • 典型收益:分析型 SQL 10× 甚至 100× 提速

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部