Oracle 12c in memory新特性
今天,简单学习一下Oracle 12c(12.1.0.2)推出的IN-MEMORY新特性,早上发生点不愉快的事情,有点闹心,可能整理的不是很全面。我的实验环境是一个2节点的RAC,操作系统版本是OEL 7.6,数据库版本是19.3.0.0.0。
IN-MEMORY特性会在SGA中单独分配一个INMEMORY_AREA区域,把全表、个别分区或者个别列以压缩或者不压缩并且以列存储的模式保存到INMEMORY_AREA区,可以极大提高对大量数据的分析。
默认情况下,SYSTEM和SYSAUX表空间里面的对象是不能使用IN_MEMORY特性的,但是可用通过修改_enable_imc_sys隐含参数的设置来控制SYSTEM和SYSAUX表空间里面的对象也可用使用这个特性,基本用不到。
启用INMEMORY_AREA特性,需要调整inmemory_size和inmemory_max_populate_servers两个参数。
SQL> show parameter inmem 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 inmemory_size big integer 0 inmemory_trickle_repopulate_servers_ integer 1 percent inmemory_virtual_columns string MANUAL inmemory_xmem_size big integer 0 optimizer_inmemory_aware boolean TRUE
其实只设置inmemory_size参数也可以,inmemory_size参数是指在SGA中分配的INMEMORY_AREA区域的大小,最小值是100MB。这个参数在12.1.0.2版本是个静态参数,调整后需要重启才能生效,在12.2版本开始,这个参数可以动态调整,但是新启动的情况下,也就是从0调整到100MB以上时,还是不能动态调整,必须重启才能生效。分解演示如下:
SQL> alter system set inmemory_size=1G sid='*'; alter system set inmemory_size=1G sid='*' * ERROR at line 1: ORA-02097: parameter cannot be modified because specified value is invalid ORA-02095: specified initialization parameter cannot be modified
直接从0调整inmemory_size参数失败,不能直接启用,需要修改参数文件,然后重启生效。
SQL> alter system set inmemory_size=1G scope=spfile sid='*'; System altered. SQL> startup force ORACLE instance started. Total System Global Area 4.1876E+10 bytes Fixed Size 30141128 bytes Variable Size 6845104128 bytes Database Buffers 3.3823E+10 bytes Redo Buffers 104075264 bytes In-Memory Area 1073741824 bytes Database mounted. Database opened.
加上SCOPE=SPFILE,在参数文件中修改inmemory_size参数,重启数据库参数设置成功。
SQL> alter system set inmemory_size=15G sid='*'; System altered.
之后,inmemory_size参数可用动态调整,即时生效。
SQL> show sga Total System Global Area 4.1876E+10 bytes Fixed Size 30141128 bytes Variable Size 7247757312 bytes Database Buffers 1.8388E+10 bytes Redo Buffers 104075264 bytes In-Memory Area 1.6106E+10 bytes
会根据inmemory_size参数的设置在SGA中分配In-Memory Area区域,inmemory_size参数大小视情况而定,分配过大会浪费内存资源,分配过小会导致数据不能全部加载到In-Memory Area区域,v$im_segments视图的POPULATE_STATUS字段会遇到OUT OF MEMORY的情况,但是不影响对表的操作,只是加速没那么彻底。
inmemory_max_populate_servers参数是控制populate_servers的个数,populate是用来将数据从硬盘加载到INMEMORY_AREA区的操作,数量默认是CPU_COUNT数的一半,populate_servers数量越多,加载的速度越快,资源消耗也越多,我这里设置为2个。这个参数是动态参数,可以直接设置,即时生效。
SQL> alter system set inmemory_max_populate_servers=2 sid='*'; System altered.
下面创建一张测试表,T_TEXT_IM,大小约12.5GB,大概1亿条记录。
SQL> conn dbdream/dbdream Connected. SQL> select segment_name,bytes/1024/1024/1024 GB from user_segments; SEGMENT_NAME GB --------------- ---------- T_TEXT_BASIC 12.5 SQL> create table t_text_im as select * from T_TEXT_BASIC; Table created. SQL> select segment_name,bytes/1024/1024/1024 GB from user_segments; SEGMENT_NAME GB --------------- ---------- T_TEXT_BASIC 12.5 T_TEXT_IM 12.5517578
这样就可以使用IN_MEMORY特性了,在做测试之前,先说一下populate的优先级,也就是什么时候把数据倒腾到内存中。
PRIORITY NONE:默认值;执行 SQL 引起对象扫描后,触发进入 IN-MEMORY PRIORITY CRITICAL:最高优先级;立即进入 IN-MEMORY PRIORITY HIGH:在具有 CRITICAL 优先级的对象之后进入 IN-MEMORY PRIORITY MEDIUM:在具有 CRITICAL、HIGH 优先级的对象之后进入 IN-MEMORY PRIORITY LOW:在具有 CRITICAL、HIGH、MEDIUM 优先级的对象之后进入 IN-MEMORY
如果在使用IN_MEMORY特性的时候不指定PRIORITY的级别,默认使用PRIORITY NONE,需要有SQL扫描那个表之后触发加载进程。
在看一下压缩方式。
NO MEMCOMPRESS:不压缩 MEMCOMPRESS FOR DML:最小化压缩,优化 DML 操作 MEMCOMPRESS FOR QUERY LOW:默认值:查询性能最优、空间压缩效果好于DML方式 MEMCOMPRESS FOR QUERY HIGH:查询性能次优(excellent)、空间压缩效果好于 QUERY LOW MEMCOMPRESS FOR CAPACITY LOW:查询性能良好(good)、空间压缩效果好于 QUERY HIGH MEMCOMPRESS FOR CAPACITY HIGH:空间压缩效果最优
如果不知道压缩方式,默认使用MEMCOMPRESS FOR QUERY LOW的压缩方式。
对RAC数据库来讲,还有一个数据分布方式需要说一下。有DISTRIBUTE和DUPLICATE两种数据分布方式。
DISTRIBUTE是默认的分布方式,是把数据分片存放到RAC的各个实例上,可以按照DISTRIBUTE BY ROWID RANGE 按 rowid 范围分布,指定 DISTRIBUTE BY PARTITION 将分区分布给不同的节点,或指定 DISTRIBUTE BY SUBPARTITION 将子分区分布给不同的节点,如果不指定,默认使用AUTO分布方式。
DUPLICATE的分布方式,是把整份数据存放在RAC的各个节点的实例中,可用指定具体节点,也可用是所有节点,也就是各个节点都存一份完整一样的数据,而不是每个节点只存部分数据。这对内存要求比较高。我参考的文档里说DUPLICATE的分布方式是EXADATA一体机专属的功能,但我用的19.3版本也可用用。
拿喝酒打个比方,DISTRIBUTE的分布方式类似于上海人喝酒,一桌人分着喝一瓶酒,每个人都喝一点;DUPLICATE就好比东北人喝酒,必须一人喝一瓶,当然有酒精过敏的可用不喝。比喻不太恰当,没有地域歧视,莫要误会。
下面把测试表开启IN_MEMORY功能。
SQL> alter table dbdream.T_TEXT_IM inmemory PRIORITY CRITICAL; Table altered.
有几个IN_MEMORY相关的视图可用查看相关的信息。V$INMEMORY_AREA、V$IM_SEGMENTS、V$IM_COLUMN_LEVEL,RAC数据库需要查询GV$相关的视图。
SQL> select OWNER,SEGMENT_NAME,INMEMORY_SIZE/1024/1024/1024 im_size_gb,BYTES/1024/1024/1024 GB,BYTES_NOT_POPULATED/1024/1024/1024 BNP,POPULATE_STATUS,INMEMORY_PRIORITY,INMEMORY_DISTRIBUTE,INMEMORY_DUPLICATE,INMEMORY_COMPRESSION,INMEMORY_SERVICE from GV$IM_SEGMENTS; OWNER SEGMENT_NAME IM_SIZE_GB GB BNP POPULATE_STAT INMEMORY INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS INMEMORY_SER --------------- --------------- ---------- ---------- ---------- ------------- -------- --------------- ------------- ----------------- ------------ DBDREAM T_TEXT_IM .051330566 12.4903259 12.1038666 STARTED CRITICAL AUTO NO DUPLICATE FOR QUERY LOW DEFAULT DBDREAM T_TEXT_IM .018371582 12.4903259 12.3500366 STARTED CRITICAL AUTO NO DUPLICATE FOR QUERY LOW DEFAULT
V$IM_SEGMENTS视图的POPULATE_STATUS字段代表的是从硬盘把数据倒腾到内存的状态,STARTED是进程已经启动,正在干;COMPLETED状态是这个活已经干完了。
下面看一下全表扫描的执行计划。
SQL> SELECT COUNT(*) FROM DBDREAM.T_TEXT_IM; COUNT(*) ---------- 97558528 Execution Plan ---------------------------------------------------------- Plan hash value: 2936459351 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16925 (3)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS INMEMORY FULL| T_TEXT_IM | 97M| 16925 (3)| 00:00:01 | --------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 846669 consistent gets 0 physical reads 0 redo size 553 bytes sent via SQL*Net to client 400 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
逻辑读846669,在看一下不使用IN_MEMORY特性时的全表扫的执行计划。
SQL> SELECT /*+no_inmemory*/ COUNT(*) FROM DBDREAM.T_TEXT_IM; COUNT(*) ---------- 97558528 Execution Plan ---------------------------------------------------------- Plan hash value: 1663429650 ------------------------------------------------------------------------ | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 444K (1)| 00:00:18 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T_TEXT_IM | 97M| 444K (1)| 00:00:18 | ------------------------------------------------------------------------ Statistics ---------------------------------------------------------- 30 recursive calls 0 db block gets 1642772 consistent gets 0 physical reads 0 redo size 553 bytes sent via SQL*Net to client 417 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
逻辑读1642772。
使用IN_MEMORY时,逻辑读846669,不使用IN_MEMORY时,逻辑读1642772,好像使用IN_MEMORY逻辑读只减少了一半,效果不是特别明显,这又要说一下parallel_degree_policy并行的问题,RAC数据库IN_MEMORY和并行配合使用,效果才会特别明显。
SQL> alter system set parallel_degree_policy=auto sid='*'; System altered. SQL> SELECT COUNT(*) FROM DBDREAM.T_TEXT_IM; COUNT(*) ---------- 97558528 Execution Plan ---------------------------------------------------------- Plan hash value: 1663429650 ----------------------------------------------------------------------------------------------------------------- | Id| Operation | Name | Rows | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | ----------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 324 (3)| 00:00:01 | | | | | 1 | SORT AGGREGATE | | 1 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | | | Q1,00 | P->S | QC (RAND) | | 4 | SORT AGGREGATE | | 1 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 97M| 324 (3)| 00:00:01 | Q1,00 | PCWC | | | 6 | TABLE ACCESS INMEMORY FULL| T_TEXT_IM | 97M| 324 (3)| 00:00:01 | Q1,00 | PCWP | | ----------------------------------------------------------------------------------------------------------------- Note ----- - automatic DOP: Computed Degree of Parallelism is 58 - parallel scans affinitized for inmemory Statistics ---------------------------------------------------------- 316 recursive calls 8 db block gets 608 consistent gets 0 physical reads 0 redo size 553 bytes sent via SQL*Net to client 400 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 5 sorts (memory) 0 sorts (disk) 1 rows processed
再测一下DUPLICATE的分布方式,我参考的资料说是EXADATA的专属功能,但我在19.3版本上测试也可用使用,其他版本是否可用使用就不清楚了。
SQL> alter table dbdream.T_TEXT_IM no inmemory; Table altered. SQL> alter table dbdream.T_TEXT_IM inmemory DUPLICATE all PRIORITY CRITICAL; Table altered. SQL> select OWNER,SEGMENT_NAME,INMEMORY_SIZE/1024/1024/1024 im_size_gb,BYTES/1024/1024/1024 GB,BYTES_NOT_POPULATED/1024/1024/1024 BNP,POPULATE_STATUS,INMEMORY_PRIORITY,INMEMORY_DISTRIBUTE,INMEMORY_DUPLICATE,INMEMORY_COMPRESSION,INMEMORY_SERVICE from gv$im_segments; OWNER SEGMENT_NAME IM_SIZE_GB GB BNP POPULATE_STAT INMEMORY INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS INMEMORY_SER --------------- --------------- ---------- ---------- ---------- ------------- -------- --------------- ------------- ----------------- ------------ DBDREAM T_TEXT_IM .051330566 12.4903259 12.1038666 STARTED CRITICAL AUTO DUPLICATE ALL FOR QUERY LOW DEFAULT DBDREAM T_TEXT_IM .018371582 12.4903259 12.3500366 STARTED CRITICAL AUTO DUPLICATE ALL FOR QUERY LOW DEFAULT SQL> / OWNER SEGMENT_NAME IM_SIZE_GB GB BNP POPULATE_STAT INMEMORY INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS INMEMORY_SER --------------- --------------- ---------- ---------- ---------- ------------- -------- --------------- ------------- ----------------- ------------ DBDREAM T_TEXT_IM .868408203 12.4903259 5.73591614 COMPLETED CRITICAL AUTO DUPLICATE ALL FOR QUERY LOW DEFAULT DBDREAM T_TEXT_IM .735778809 12.4903259 6.75440979 COMPLETED CRITICAL AUTO DUPLICATE ALL FOR QUERY LOW DEFAULT SQL> select count(*) from DBDREAM.T_TEXT_IM; COUNT(*) ---------- 97558528 Execution Plan ---------------------------------------------------------- Plan hash value: 1663429650 ----------------------------------------------------------------------------------------------------------------- | Id| Operation | Name | Rows | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | ----------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 324 (3)| 00:00:01 | | | | | 1 | SORT AGGREGATE | | 1 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | | | Q1,00 | P->S | QC (RAND) | | 4 | SORT AGGREGATE | | 1 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 97M| 324 (3)| 00:00:01 | Q1,00 | PCWC | | | 6 | TABLE ACCESS INMEMORY FULL| T_TEXT_IM | 97M| 324 (3)| 00:00:01 | Q1,00 | PCWP | | ----------------------------------------------------------------------------------------------------------------- Note ----- - automatic DOP: Computed Degree of Parallelism is 58 - parallel scans affinitized for inmemory Statistics ---------------------------------------------------------- 242 recursive calls 8 db block gets 612 consistent gets 0 physical reads 0 redo size 553 bytes sent via SQL*Net to client 400 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 7 sorts (memory) 0 sorts (disk) 1 rows processed
参考文献:
https://www.cnblogs.com/fyy-hhzzj/p/9083456.html
http://www.pianshen.com/article/2447218719/
【下一篇】ORA-28000 the account is locked错误