IMO,即In-Memory Option。为Oracle 12c中最为重要的新特性之一。12.1开始支持该新特性。
目录
- 基本介绍
- 可以启用In-Memory列存储功能的级别
- 适合使用IMO功能的操作类型
- 可以使用INMEMORY子句的命令
- 查询数据库中哪些segment启用了IM
- 不适合使用IM的操作
- 数据压缩
- IM的存储设置
- 与IMO相关的初始化参数
- 在表,表空间,或者物化视图上启用IM
- 与IM相关的等待事件
- 与IM相关的统计信息
一.基本介绍
In-Memory列存储组件,为12c 中SGA的可选组件。可以用来存储表、表分区、以及其他数据库对象的副本。启用该选项,我们可以在SGA中按列存储某些对象,而不是原来的按行存储。
ps:看到按列存储,会有人想到Sybase的IQ数据库咩?
In-Memory列存储是SGA中的一个新的静态池(static pool)。所谓静态,也就是说里面的对象需要我们dba手工管理。在该池中,数据都是按列存储,而原来sga的db buffer cache中,数据依然还是按行存储。这样,整个内存,就可以同时提供数据的按行和按列存储。要启用该选项,INMEMORY_SIZE参数,需要设置为非零值。当然,不能小于100M,否则,你会碰到如下错误:
二. 可以启用In-Memory列存储功能的级别
- Column
- Table
- Materialized view
- Tablespace
- Partition
如果在表空间级别上启用该功能,则所有存储在该表空间中的表和物化视图都将继承这一功能。
三. 适合使用IMO功能的操作类型
- A query that scans a large number of rows and applies filters that use operators such as the following: =, <, >, and IN
- A query that selects a small number of columns from a table or materialized view with a large number of columns, such as a query that selects five columns from a table with 100 columns 查询一个多列对象中的少数几列
- A query that joins a small table to a large table
- A query that aggregates data
需要注意的一个点:一般情况下,复合索引可以用来提升某些分析或者报表查询的性能。但是,当数据为按列存储时,这些索引,基本就不需要了。
四. 可以使用INMEMORY子句的命令
- CREATE TABLE
- ALTER TABLE
- CREATE TABLESPACE
- ALTER TABLESPACE
- CREATE MATERIALIZED VIEW
- ALTER MATERIALIZED VIEW
五. 查询数据库中哪些segment启用了IM
想查询当前数据库中哪些segment启用了IM,可以执行如下查询语句:
SELECT OWNER, SEGMENT_NAME, INMEMORY_PRIORITY, INMEMORY_COMPRESSION
FROM V$IM_SEGMENTS;
例如:
注意这个查询的后两列:
INMEMORY_PRIORITY,优先级设置,如果没有设置则为none。
INMEMORY_COMPRESSION 压缩级别,也就是说,可以压缩存储。
需要注意的是,数据库对象即便启用了IM,该对象也不一定就会放到内存中。所以,执行该查询,可能无法查到你想要的结果。比如:
--查询结果当中木有啊,那把这张表在IM中的优先级设置一下看看。
--注:关于优先级,我们后面再说。
--恩,还是木有。是优先级太低了?
在对表tab_test启用IM时,即便设置了最高的优先级,也还是查询不到。
在这里稍微推测一下,应该跟表的数据量相关。
六. 不适合使用IM的操作
- Queries with complex predicates
- Queries that select a large number of columns
- Queries that return a large number of rows
- Queries with multiple large table joins
另外,如果对象的所有者为sys,或者是存储在SYSTEM 或SYSAUX表空间中的,则无法使用IM选项。
七. 数据压缩
在IM列存储选项中,可以将数据压缩,然后缓存到内存中。压缩选项如下:
IM操作,可以分别针对DML、query以及capacity等数据缓存用途进行不同级别的压缩,压缩级别越高,可存储的对象也就越多,但是性能就会下降。
来看个例子:
可以看到压缩效果。
注:这两个测试表都是通过CTAS方式以dba_objects中的数据创建。
八. IM的存储设置
IM占用的是SGA的空间,由参数inmemory_size手动控制。
但是该参数为上限设置,如果要启用IM选项的对象大小加起来超过了该参数的值,那怎么办?
当我们对多个对象启用IM时,我们可以让oracle自己来处理,看看空间不够的时候,oracle会把哪些对象移出IM。
另外一种方法,则是在给对象启用IM时设置优先级。
IM中可以设置的优先级如下:
表格中的优先级从低到高,优先级越高,往IM里面存放的时候,就越优先考虑。实质上,算是对要缓存对象的优先级排序,以便oracle在IM空间不足的时候,知道如何处理对象。
当数据库重启时,所有优先级为非none的对象,都将在数据库启动过程中缓存到IM中。
需要注意的是:
1,优先级只能应用于表或者表的分区级别,而无法应用到列级别上。
2,如果对象小于64K,则该对象不会存放到IM中。前面的tab_test就是如此。
来看实验:
数据库版本12.1.0.2,os版本rhel6.4,本IM系列文章均是如此。
ok,那么,如果启用IM的表,数据量发生了变化,那IM能自己探测么?
往下看:
但是我又查了下统计信息收集,user_tables里面反倒木有更新:
注意蓝色的内容,行数和统计信息收集时间都没有发生变,但是IM中的却都变化了。
另外,我又测试了下tab_obj3,将其优先级从high降至low,然后也是立马就被丢出IM了········
稍微总结一下:
1.即便设置了表的inmemory选项,也必须要在访问表中数据之后,才会被缓存到IM中。
2.已经缓存在IM中的表,如果降低其优先级,将会被从IM中移除(实际上,只要优先级发生改变,则该表就会被移除。这一点,各位可以自行测试确认)。
3.IM会自动感知存放在IM中的表的数据变化,但是原有以行模式存储的数据的统计信息,则不会自动更新。
继续做实验:
也就是说,如果给表启用了IM,即便这张表没有被存入到IM中,其执行计划显示也会是TABLE ACCESS INMEMORY FULL。
当然,实际的执行计划显然不会是这个。这一点,我们需要注意。
九. 与IMO相关的初始化参数
INMEMORY_SIZE:IM使用的内存空间大小,默认为0。如果非零,则不得小于100M。但是在多租户环境下,单个pdb的IM size,便不受CDB中该参数大小的制约,如果你手工设置某一个或者某几个PDB的IM size的话。如果不单独设置,则各个pdb直接继承CDB中该参数的设置。
INMEMORY_FORCE:是否启用IM,如果为default,则启用;为off,不启用。
INMEMORY_CLAUSE_DEFAULT:该参数指定了默认的IM子句的内容。如果为空,也就是其默认值,等同于no inmemory。但是如果指定了非空值,则会改变IM的默认设置。
例如:
alter system set
INMEMORY_CLAUSE_DEFAULT='INMEMORY MEMCOMPRESS FOR CAPACITY HIGH'
scope=spfile;
然后重启数据库,选择一张表,启用IM:
alter table tab_test inmemory;
则等同于:
alter table tab_test inmemory memcompress for capacity high;
INMEMORY_QUERY:指定是否启用IM查询。将其设置为enable,则启用;disable,则不启用。
INMEMORY_MAX_POPULATE_SERVERS:该参数指定了处理IM数据的最大后台进程个数。依赖于系统的cpu内核数目,有点类似于并行进程相关的参数设置。
INMEMORY_TRICKLE_REPOPULATE_SERVERS_PERCENT: 该参数用于控制IM中对象数据的重新载入的进程数,该值为INMEMORY_MAX_POPULATE_SERVERS参数的百分比。
OPTIMIZER_INMEMORY_AWARE:用于控制CBO是否使用IM选项,为false,则忽略;为true,则考虑。
十. 在表,表空间,或者物化视图上启用IM
要在表,表空间,或者物化视图上启用IM功能,你需要先在数据库级别启用IM选项,也就是说,你要满足如下条件:
1.数据库版本在12.1.0或者以上。
2.inmenory_size设置为100M或者以上。
3.重启数据库
4.查看下当前im可以使用的内存大小:
show parameter inmemory_size。
当然,这一步可选。
与表相关的IM的几个例子:
1.在创建表时直接启用IM:
CREATE TABLE test_inmem (
id NUMBER(5) PRIMARY KEY,
test_col VARCHAR2(15))
INMEMORY;
2.创建表完成之后,使用alter命令启用IM:
ALTER TABLE oe.product_information INMEMORY;
3.启用IM并设置压缩级别:
ALTER TABLE oe.product_information INMEMORY
MEMCOMPRESS FOR CAPACITY LOW;
4.启用IM并设置优先级:
ALTER TABLE oe.product_information INMEMORY PRIORITY HIGH;
5.启用IM并同时设置压缩级别和优先级:
ALTER TABLE oe.product_information INMEMORY
MEMCOMPRESS FOR CAPACITY HIGH
PRIORITY LOW;
6.对表中部分列组合启用IM,并设置压缩级别:
注:可以查看v$im_column_level视图来了解列的压缩级别。
7.关闭IM:
ALTER TABLE oe.product_information NO INMEMORY;
再注:对于列,无法设置单独的优先级,只能对表,或者表分区设置。
又注:可以通过查看v$im_segments来了解哪些对象已经被缓存到了IM中。
与表空间相关的几个IM的例子:
1.在创建表空间时启用IM:
CREATE TABLESPACE tbs1
DATAFILE 'tbs1.dbf' SIZE 40M
ONLINE
DEFAULT INMEMORY;
注:因为我们没有指定该表空间的压缩级别及优先级,所以其默认值为MEMCOMPRESS FOR QUERY, 以及 PRIORITY NONE。
2.使用alter命令修改表空间的IM选项设置:
ALTER TABLESPACE tbs1 DEFAULT INMEMORY
MEMCOMPRESS FOR CAPACITY HIGH
PRIORITY LOW;
与物化视图相关的IM的几个例子:
1.创建物化视图时启用IM:
CREATE MATERIALIZED VIEW oe.prod_info_mv INMEMORY
AS SELECT * FROM oe.product_information;
注:此时的压缩级别及优先级设置,与上面表空间的默认设置一样。
2.创建后修改IM设置:
ALTER MATERIALIZED VIEW oe.prod_info_mv INMEMORY PRIORITY HIGH;
Data Pump中的im应用:
在impdp对象的时候,可以指定如下选项
TRANSFORM=INMEMORY:y 保留导出对象的IM设置
TRANSFORM=INMEMORY:n 不保留导出对象的IM设置
TRANSFORM=INMEMORY_CLAUSE:string 在导入时重新设置导出时的IM设置
当然,你也可以在EM中使用IM
12c中,与IM相关的数据字典表,我特意去查了下官方文档,无论是cdb,dba,all还是user打头的,基本都没有相关的内容。于是我搜了下v$开头的视图,查询结果如下:
这其中,V$IM_COLUMN_LEVEL和V$IM_SEGMENTS两个在前面已经涉及到过。我们这里统一把这些视图说一下:
V$INMEMORY_AREA:启用IM的对象所占用的内存空间。查询该视图,你就会知道,IM用于存储对象的内存区域,分为两个部分,一个以1M为分配单位,用于存储列数据,另外一个以64K为分配单位,用于存储对象的元数据(metadata)和事务日志(transaction journal)。
来看例子:
V$IM_COLUMN_LEVEL:用于记录列的压缩级别。
V$IM_COL_CU:记录IMCU中基于列的统计信息。
V$IM_HEADER:记录IM区对象所分配IMCU的详细信息。
V$IM_SEGMENTS:记录存储在IM中的段的属性。
V$IM_SEGMENTS_DETAIL:记录存储在IM中的段的详细属性(至于详细到什么程度,各位去对比这两个视图的列名即可。
V$IM_SEG_EXT_MAP:记录IM区对象的所有区间映射关系。
V$IM_SMU_CHUNK:记录IM中对象的元数据的块信息。
V$IM_SMU_HEAD:记录IM中对象的元数据的头信息。
V$IM_TBS_EXT_MAP:记录IM区1M子池对象的区间映射关系。
V$IM_USER_SEGMENTS:记录当前用户下IM段对象的存储属性。
*IMCU 是In Memory Compression Units
是数据在内存中分配的块的大小,比较类似于数据库中extent的概念。后台进程ora_w00*在装载数据时,会分配自己的IMCU,并将分配给该进程的数据加载到该IMCU中。此后,当访问IM区中的列数据时,我们在统计信息中看到的consistent gets值也就是统计所访问IMCU的个数和所需访问metadata块的个数之和。特定对象所分配IMCU的详细信息,可从视图V_$IM_HEADER中查询。而其metadata块的信息可从视图V_$IM_SMU_CHUNK和V_$IM_SMU_HEAD查询。
在In Memory内部,以IMCU为单位,Oracle维护了一个In Memory Storage Index,记录IMCU单元中该列的最大值,最小值。此外,Oracle也会在metadata区为每个IMCU建立相应的metadata dictionary, metadata信息中会有一些列的统计信息。视图V_$IM_COL_CU可以帮助查询这些metadata dictionary信息。
十一.与IM相关的等待事件
十二. 与IM相关的统计信息
作者介绍:史跃东
- TJOUG发起人,Oracle 10g/11g OCM。
- 超过九年的数据库、数据仓库及相关行业经历。
- 目前从事oracle数据库培训行业。专注于Oracle、MySQL技术,也进行大数据,云计算等相关技术的研究。