Bo's Oracle Station

【博客文章2022】 In-Memory Column Store系列1

2022-3-24 11:20| 发布者: admin| 查看: 162| 评论: 0|原作者: Bo Tang

摘要: In-Memory Column Store系列1,介绍了:In-Memory Column Store的工作原理、In-Memory Column Store的使用场景、In-Memory Column Store的配置和 In Memory DDL子句。
【博客文章2022】In-Memory Column Store系列1

Author: Bo Tang

1. In-Memory Column Store的工作原理:

    Oracle数据库传统上是“行格式”存储数据的,“行格式”中的所有列都存储在一起。从ER图上看,表数据的每一列代表数据的一个属性,这些属性存储在同一行中。OLTP环境往往要访问表数据的所有列,因此“行格式”存储数据是适合的。 但是,OLAP环境往往只需要访问表数据的某一两列。从ER图上看,OLAP只需要表数据的一两个属性,不需要查看其他属性。OLAP还要求尽量迅速地分析出结果。对于“行格式”存储的数据,由于要访问所有存储在一起的列,实际上只要访问一两个列,但是访问了不需要的列进而拖慢了时间,因此并不适合这种应用场景。
     Oracle Database In-Memory option引入了一种额外的存储数据的格式:“列格式”。这种额外的“列格式”把表数据逆时针旋转90度存储成列结构。这种格式适合OLAP应用场景。它适合面对大部分行快速获取其一两个列(比如对一两个列做组函数计算)来处理分析结果。In-Memory option的目标是:1)提速OLAP100倍;2)加速2倍混合负载的OLTP,同时不必复制数据到另外一个数据库专门进行OLAP;3)对前台应用透明;4)容易实施。
    在Oracle Database In-Memory option引入之前,为了分析实时数据,人们通常直接在OLTP数据库上运行OLAP。 这种混合的工作负载会使整个数据库运行变慢。如果为了加速OLAP的响应去添加专用于分析的索引,这些索引又会严重影响OLTP的执行效率。这种矛盾状态已经存在了数十年。引入Oracle Database In-Memory option之后,以上这些问题迎刃而解了。它处理这些问题的原理是:在内存中把表数据存储成"dual-format" 双重格式,即:原来的db buffer cache里存储的是“行格式”,用于OLTP;新的in-memory缓存区里存储同一个表数据相应列(不是所有列)的“列格式”,用于OLAP。
    In-Memory column store指的就是这个
新的in-memory缓存区。如果配置了,它只存在于SGA区中不存在于表空间中,它里头的数据都是列结构的。In-Memory column store按需求来缓存列结构,并不是把表所有列都缓存,因此大约只会多占用20%的内存空间。它与“行格式”的db buffer cache同时使用,见下图:

    从上图中可以看出:1)同一个表在内存中有着双重的结构,2)内存中这两种结构同时激活并且保持着一致性,3)OLTP用户使用db buffer cache,其访问方向为行方向,4)OLAP使用In-Memory column store,其访问方向为列方向。当需要访问数据时,Oracle数据库的优化器能够根据访问类型(OLTP/OLAP)自主地选择使用db buffer cache或者IM column store或者两者都用。应用代码不需要做任何更改。IM column store仅仅存在于内存中,在数据库表空间上没有任何变化,redo和undo也没有任何变化。 反过来,数据库表空间里的所有对象都可以被In-Memory column store支持。In-Memory column store用于OLAP查询时,不会产生任何redo log,里头的列数据经过2x-20x的压缩。DML操作不会使用 In-Memory column store,它只会使用传统的db buffer cache,产生的redo/undo都和原来一样。DML的更改结果通过内部同步机制当然会更新到In-Memory column store中。
     In-Memory column store是SGA区的一个静态池(静态指的是不可在线动态更改大小)。它的大小由初始化参数INMEMORY_SIZE(默认是0,就是禁用)设定,该值最小为100M。In-Memory column store又细分为两类子池子:多个IMCU池 (In-Memory Compression Units,每一个列填充Worker都有它自己的IMCU池,每个IMCU池的单位都是1M的,里头存储的是经过压缩后的实际列数据);多个SMU池(Snapshot Metadata Units,用于存储填充进In-Memory column store里的对象的元数据和事务信息,每个SMU池的单位都是64K的)。在In-Memory column store中IMCU池占大部分内存空间,典型地占领94%的空间(百分比受隐含参数_inmemory_64k_percent控制)。一些被叫做Worker后台进程(ora_w***_实例名)负责填充 In-Memory column store。每一个Worker后台进程被指定填充数据库里的一部分数据块。填充过程伴随压缩过程迅速进行,在这个过程中列数据并没有被排序。填充过程中不影响数据库的正常使用。


    在IMCU中,表中的每个列存储成的独立连续的“列压缩单元”(CU),CU中同时也存储该列的最大值和最小值,表的伪列ROWID也被存储为一个独立连续的 “列压缩单元”(CU)中。每一个CU都包含该列的最大值和最小值,压缩算法包含:1)Dictionary Compression;2)Run Length Encoding;3)Bit Packing等等。
    与In-Memory column store相关的7个主要的初始化参数如下:
    INMEMORY_SIZE: 设置In-Memory column store的大小,必需将其设置成非0值才能使用。在多租户环境下,既可以设置在根容器上也可以设置在插件数据中(限制该插件数据库能使用到的In-Memory column store的最大值,否则该插件数据库就能用到与根容器一样大的值)。
    INMEMORY_FORCE
In-Memory column store的总开关,将其关闭则任何对象都不会填充进入In-Memory column store。该参数的默认值是“DEFAULT”,允许每个数据库对象根据所设置的“INMEMORY”或”NO INMEMORY”属性来填充或不填充In-Memory column store。
    INMEMORY_QUERY :控制查询优化器用或不用
In-Memory column store
    INMEMORY_CLAUSE_DEFAULT: 为新表或新的物化视图指定默认的
INMEMORY”或”NO INMEMORY”子句。子句可以包含有效的压缩语法和数据填充选项。
    INMEMORY_MAX_POPULATE_SERVERS :指定了填充Worker进程的最大个数。一般基于系统的CPU核数设置这个参数。
    INMEMORY_OPTIMIZER_AWARE: 让CBO优化器产生执行计划的时候,考虑
In-Memory column store这种访问方式。将它设置为FALSE,优化器不会考虑In-Memory column store这种访问方式。
    INMEMORY_TRICKLE_POPULATE_SERVERS_PERCENT
INMEMORY_MAX_POPULATE_SERVERS规定的值的百分比成为当前运行的填充Worker的个数。

2. In-Memory Column Store的使用场景:
   
    在EBS套件查询、在线实时分析和数据仓库性质的负载中,In-Memory Column Store帮助最大。单纯的OLTP场景帮助甚小。
    In-Memory column store百倍加速了列scan、 join和组函数。尤其是如下的场景:
    a) 在大量的行上做几个列的scan操作,并且在这些列上使用 =、<、 >、IN和BETWEEN/AND做为过滤条件
    b) 只查询表上的几个列,而不是所有列
    c) 通过转换小的维度表上的谓词成为大的事实表的过滤条件来加速join(星型转换查询)
    使用
In-Memory Column Store后对数据库的影响:
    a)所有的数据库功能特性(比如RAC和dataguard以及多租户)都不受影响
    b)SQL和PL/SQL代码不需要做任何改动,优化器会自主考虑要不要利用
In-Memory Column Store
    c) 配置非常简单,大体上只有两个步骤:INMEMORY_SIZE初始化参数指定
In-Memory Column Store的总的大小,配置了它就开启了In-Memory Column Store; 在表空间、表、分区或列上指定哪些列要被读取进入In-Memory Column Store
    d)
In-Memory Column Store里的数据可以使用各种技术来进行压缩以增加有效内存带宽,同时以使更多的数据可以被读进In-Memory Column Store,而这种压缩是对查询友好的,并不会显著降低查询速度。
    e)使用了
In-Memory Column Store后,原先所需要的索引、物化视图和OLAP数据立方数量都会减少。这样既节省了存储成本又节约了数据库处理这些对象的时间。    
    In-Memory column store并不适合以下的场景:
    a)谓词非常复杂的查询
    b)查询大量列的查询
    c)结果集巨大的查询
    d)多个大表做连接的查询
    e)sys的表、system表空间上的表和sysaux表空间上的表都不能实现In-Memory Column Store

3. In-Memory Column Store的配置:

    从12.1.0.2以后,Oracle数据库的In-Memory option是默认无缝集成在Oracle核心中的,不需要安装,也不能选择不装。但是In-Memory Column Store默认并没有在SGA区里配置出来,同时也没有在表空间、表、分区或列上指定哪些列要被读取进入In-Memory Column Store。要使用In-Memory Column Store,配置非常简单。大体上只有两个步骤:INMEMORY_SIZE初始化参数指定In-Memory Column Store的总的大小,配置了它就开启了In-Memory Column Store; 在表空间、表、分区或列上指定哪些列要被读取进入In-Memory Column Store。
    需要先在数据库实例中配置才能使用这个功能。实际上只要配置1个叫做inmemory_size初始化参数,打开一个新的内存池子来使用它。这个参数不是动态可修改参数,必需重启数据库服务器来配置。
    未配置前查看以下3个指标:

 
SQL> show parameter inmemory;
-----------------------------------------
NAME                                               TYPE        VALUE                                                                                               
-------------------------------------------------- ----------- ----------------------------------------------------------------------------------------------------
inmemory_adg_enabled            boolean TRUE                                                                                           
inmemory_automatic_level        string  OFF                                                                                             
inmemory_clause_default          string                                                                                                      
inmemory_expressions_usage   string  ENABLE                                                                                       
inmemory_force                         string  DEFAULT                                                                                     
inmemory_max_populate_servers integer 0                                                                                                 
inmemory_optimized_arithmetic string  DISABLE                                                                                      
inmemory_prefer_xmem_memcompress string                                                                                                      
inmemory_prefer_xmem_priority string                                                                                                      
inmemory_query                        string  ENABLE   控制会话或实例级别上是否启用
In-Memory Column Store来执行查询                                                                                   
inmemory_size                          big integer 0                                                                                                 
inmemory_trickle_repopulate_servers_percent integer 1                                                                                                 
inmemory_virtual_columns        string  MANUAL                                                                                     
inmemory_xmem_size               big integer 0                                                                                                 
optimizer_inmemory_aware      boolean TRUE 


    开始配置INMEMORY_SIZE初始化参数:

 
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
Total System Global Area 2147481656 bytes
Fixed Size            8898616 bytes
Variable Size         1426063360 bytes
Database Buffers      486539264 bytes
Redo Buffers            7876608 bytes
In-Memory Area          218103808 bytes
Database mounted.
Database opened.
  
 
    配置后查看以下3个指标:

SQL> select  pool,alloc_bytes,used_bytes from V$INMEMORY_AREA;
--------------------------------------------
1MB POOL    149946368     0
64KB POOL    50331648     0


    但是,由于在表空间、表、分区或列上还没有指定哪些列要被读取进入In-Memory Column Store,所以上面的“used_bytes”为0。

 
SQL> select  * from v$sga;
--------------------------------------
Fixed Size    8898616    0
Variable Size    1140850688    0
Database Buffers    771751936    0
Redo Buffers    7876608    0
In-Memory Area    218103808    0
 
4. In Memory DDL子句:

4.1 使用默认选项开启in-memory:
    in-memory子句可以在对象或表空间级别上,也可以在创建之时或创建之后指定哪些列要被读取进入In-Memory Column Store
  prods表以默认选项开启in-memory功能:
    
    inmemory_compression: 代表列压缩等级。Oracle提供很多压缩技术进而提供不同的压缩等级供选择,不同的压缩等级的性能不同。 默认压缩等级是“FOR QUERY LOW“,提供了最好的压缩比率和性能之间的平衡。 通过MEMCOMPRESS子句来设定。

4.2 关闭in-memory,使用默认选项重新开启in-memory

 
4.3 对已有的表改变填充优先级

 
 
    这样,这个表会比优先级为“NONE”,“LOW”和“MEDIUM”的表优先填充。


 
SQL> desc promotions;
Name                       Null?    Type
 ----------------------------------------- -------- ----------------------------
 PROMO_ID                   NOT NULL NUMBER(6)
 PROMO_NAME                   NOT NULL VARCHAR2(30)
 PROMO_SUBCATEGORY               NOT NULL VARCHAR2(30)
 PROMO_SUBCATEGORY_ID               NOT NULL NUMBER
 PROMO_CATEGORY                NOT NULL VARCHAR2(30)
 PROMO_CATEGORY_ID               NOT NULL NUMBER
 PROMO_COST                   NOT NULL NUMBER(10,2)
 PROMO_BEGIN_DATE               NOT NULL DATE
 PROMO_END_DATE                NOT NULL DATE
 PROMO_TOTAL                   NOT NULL VARCHAR2(15)
 PROMO_TOTAL_ID                NOT NULL NUMBER
 
    查看列级的in-memory定义:

 
    注意那些没有在“inmemory (promo_name, promo_category, promo_cost, promo_total)”语句中明确指定的列,也是开启了in-memory。另外,如果整个表disable了in-memory,那么所有列也都disable了in-memory。
    设置这个表空间默认开启in-memory,并指定in-memory压缩属性为“FOR CAPACITY HIGH”,优先级设置为“HIGH”。

SQL> alter tablespace users default inmemory memcompress for capacity high priority high;
   
    查看users表空间有无默认in-memory定义:

 
    在这个表空间上创建一个表,不加任何inmemory子句:

 
    查看这个表是否继承了表空间的inmemory属性:

SQL> select  inmemory, inmemory_compression, inmemory_distribute, inmemory_duplicate, inmemory_priority  from user_tables  where table_name='T1';
-------------------------------------------------------------------------------------------------
ENABLED    FOR CAPACITY HIGH    AUTO    NO DUPLICATE    HIGH
 
    答案是肯定的。
   在这个表空间上再创建一个表,加不同于表空间默认inmemory子句的选项:

 
    查看这个表是否有不同于表空间的inmemory属性:

SQL> select  inmemory, inmemory_compression, inmemory_distribute, inmemory_duplicate, inmemory_priority  from user_tables  where table_name='T2';
-------------------------------------------------------------------------------------------------
ENABLED    FOR QUERY HIGH    AUTO    NO DUPLICATE    LOW
 
    答案是肯定的。

4.6 INMEMORY_CLAUSE_DEFAULT默认语句:
   还可以通过设置INMEMORY_CLAUSE_DEFAULT来设置建表或物化视图时的默认添加的inmemory选项。优先生效的级别是:创建对象时明确指定>表空间上的默认指定>INMEMORY_CLAUSE_DEFAULTINMEMORY_CLAUSE_DEFAULT的取值可以是“inmemory memcompress ......”,也可以是“memcompress ......”,使用后者,在建表时要补写“immemory”后者没有开启in-memory选项。

路过

雷人

握手

鲜花

鸡蛋

QQ|手机版|Bo's Oracle Station   

GMT+8, 2022-4-24 10:36 , Processed in 0.042753 second(s), 21 queries .

返回顶部