概述

目前Oracle LiveLabs上关于Oracle Database In-Memory的内容已更新,主要变化为:

  • 数据库使用21c
  • 增加了对21c原生JSON的实验
  • 增加了21c AIM HIGH级别的实验

这个实验的名称为Boost Analytics Performance with Oracle Database In-Memory。

实验帮助在这里。

实验环境描述

实验环境的生成需要约8分钟。这是一个2 OCPU(4 vCPU), 32G内存的机器。如果自己搭建环境,只需要16GB的内存就够了。

[oracle@dbhol:~]$ lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              4
On-line CPU(s) list: 0-3
Thread(s) per core:  2
Core(s) per socket:  2
Socket(s):           1
NUMA node(s):        1
Vendor ID:           AuthenticAMD
CPU family:          25
Model:               1
Model name:          AMD EPYC 7J13 64-Core Processor
Stepping:            1
CPU MHz:             2445.406
BogoMIPS:            4890.81
Virtualization:      AMD-V
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           64K
L1i cache:           64K
L2 cache:            512K
L3 cache:            16384K
NUMA node0 CPU(s):   0-3
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core invpcid_single ssbd ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves nt_good clzero xsaveerptr wbnoinvd arat npt nrip_save umip pku ospke vaes vpclmulqdq rdpid arch_capabilities[oracle@dbhol:~]$ free -gtotal        used        free      shared  buff/cache   available
Mem:             31           3          17           6          10          21
Swap:             7           0           7

尽管提供了图形化VNC远程连接的方式,但也可以用putty直接登录虚机,这样更方便。方法请参见“Lab 1: Environment Setup”,此不赘述。

数据库版本为21.7,数据库是PDB1,用到了SSB和AIM两个schema:

Connected to:
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.7.0.0.0SQL> show pdbsCON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------2 PDB$SEED                       READ ONLY  NO3 PDB1                           READ WRITE NOSQL> select username from all_users where ORACLE_MAINTAINED != 'Y';USERNAME
--------------------------------------------------------------------------------
PDBADMIN
AIM
SSB

SSB schema中的5张标准表均启用了压缩,以下命令只是说明,无需运行:

alter table lineorder move compress basic;
alter table part move compress basic;
alter table date_dim move compress basic;
alter table supplier move compress basic;
alter table customer move compress basic;
alter table storage(buffer_pool keep);

同时也都放在了指定的buffer pool中,以下命令只是说明,无需运行:

alter table lineorder storage(buffer_pool keep);
alter table part storage(buffer_pool keep);
alter table date_dim storage(buffer_pool keep);
alter table supplier storage(buffer_pool keep);
alter table customer storage(buffer_pool keep);

这5张表的数据生成可用以下命令:

./dbgen -s 10 -T c
./dbgen -s 10 -T s
./dbgen -s 10 -T p
./dbgen -s 10 -T l
./dbgen -s 1 -T d

然后导入数据后,将lineorder变为分区表,并删除2个分区:

alter table lineorder modify partition by range(lo_orderdate)
(partition part_1992 values less than ('19930101'),partition part_1993 values less than ('19940101'),partition part_1994 values less than ('19950101'),partition part_1995 values less than ('19960101'),partition part_1996 values less than ('19970101'),partition part_1997 values less than ('19980101'),partition part_1998 values less than ('19990101')
);alter table lineorder drop partition part_1992;
alter table lineorder drop partition part_1993;

实验2:初始化环境

任务 1:为内存中用例初始化数据库

首先,需要用oracle用户下载实验脚本:

clear
cd ~oracle/labs
rm -rf ~oracle/labs/*
wget -O novnc-inmemory-21c.zip https://objectstorage.us-ashburn-1.oraclecloud.com/p/7lzqJmKirEWwAc-e4XbZhV0A9ZYzqv7jU6HRhADWpR5zbhHb3x3rKjZV3m5ktDD0/n/c4u04/b/livelabsfiles/o/labfiles/novnc-inmemory-21c.zip
unzip -qo novnc-inmemory-21c.zip
rm -f novnc-inmemory-21c.zip
cd inmemory
ls -ltrh

由于此环境的模板有2个CDB,CDB1和CDB2。而我们只需要CDB1,因此需要停掉CDB2:

sudo systemctl stop oracle-database
sudo sed -i -e 's|CDB2.*$|CDB2:/opt/oracle/product/21c/dbhome_1:N|g' /etc/oratab
sudo systemctl start oracle-database
ps -ef|grep ora_|grep pmon|grep -v grep

而方法是在oratab中将CDB2的条目改为N:

$ cat /etc/oratab
CDB1:/opt/oracle/product/21c/dbhome_1:Y
CDB2:/opt/oracle/product/21c/dbhome_1:N

修改~/labs/inmemory目录下,以下两个文件中ssb和aim用户的口令:

$ ls *login.sql
aim_login.sql  imlogin.sql

任务 2:启用In-Memory

运行以下脚本,初始化环境变量:

. ~/.set-env-db.sh CDB1

我们来研究下这个脚本,其中有很多值得学习之处,详见其中的中文注释:

#!/bin/bash
# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.################################################################################
#
# Name:set-env-db.sh
#
# Description: Script to set the database environment (single instance) in multiple
#             Oracle homes setup
#
#
#  Pre-requisite: This should be executed as the user that owns Oracle DB binaries.
#
#  AUTHOR(S)
#  -------
#  Rene Fontcha, Oracle LiveLabs Platform Lead
#
#  MODIFIED        Date                 Comments
#  --------        ----------           -----------------------------------
#  Rene Fontcha    10/18/2021           Initial Creation
#  Rene Fontcha    05/19/2022           Replaced Public IP lookup routine
#  Rene Fontcha    07/19/2022           Added "Oracle LiveLabs" branding banner
#
###############################################################################
PRIVATE_IP=$(cat /etc/hosts | grep $(hostname) | grep -v grep |tail -1 | awk '{print $1}')
HOSTNAME=$(hostname)## 如果有多个私网IP地址,以下会得到所有列表
if [ -z ${PRIVATE_IP} ]; thenPRIVATE_IP=$(oci-metadata -g privateIp | sed -n -e 's/^.*Private IP address: //p')
fiexport PRIVATE_IP
## 得到公网地址,这个命令不错
export PUBLIC_IP=$(curl -s ifconfig.me)
unset ORACLE_SIDif [ -f /etc/oratab ]; thenOTAB=/etc/orataboratab_exist=Y
elif [ -f /var/opt/oracle/oratab ]; thenOTAB=/var/opt/oracle/orataboratab_exist=Y
elseoratab_exist=Necho 'oratab file not found.'
fi
load_env_header() {clearecho "================================================================================"
## figlet 需 yum安装,类似于banner,-c表示居中
##  figlet -c Oracle LiveLabsecho "================================================================================"echo "                       ENV VARIABLES                                            "echo "--------------------------------------------------------------------------------"
}load_db_env() {export ORAENV_ASK=NO. oraenv >/dev/nullexport ORAENV_ASK=YESexport OH=${ORACLE_HOME}
## 这个确定TNS_ADMIN的方法不错,即21c增加的orabasehomeif [ -f ${OH}/bin/orabasehome ]; thenexport ORACLE_BASE_HOME=$(orabasehome)export TNS_ADMIN=${ORACLE_BASE_HOME}/network/adminelseexport TNS_ADMIN=${OH}/network/adminfiexport LD_LIBRARY_PATH=$OH/libexport PATH=${OH}/bin:${OH}/OPatch:${JAVA_HOME}/bin:/bin:/usr/ccs/bin:/usr/sfw/bin:/usr/bin:/usr/sbin:/usr/ucb:/etc:/usr/local/bin:/usr/dt/bin:/usr/openwin/bin:/opt/sfw/bin/:.:~:/sbin:/usr/X11R6/bin:$PATHalias ssql="$OH/bin/sql / as sysdba"echo " . ORACLE_BASE         = ${ORACLE_BASE}"if [ -f ${OH}/bin/orabasehome ]; thenecho " . ORACLE_BASE_HOME    = ${ORACLE_BASE_HOME}"fiecho " . ORACLE_HOME         = ${OH}"echo " . ORACLE_SID          = ${ORACLE_SID}"echo " . PRIVATE_IP          = ${PRIVATE_IP}"echo " . PUBLIC_IP           = ${PUBLIC_IP}"echo " . HOSTNAME            = ${HOSTNAME}"echo "--------------------------------------------------------------------------------"echo "                       Database ENV set for ${ORACLE_SID}                       "echo "                                                                                "echo " Run this to reload/setup the Database ENV: source /usr/local/bin/.set-env-db.sh"echo "--------------------------------------------------------------------------------"echo "================================================================================"echo " "
}
#
#############################################################################
# Display Info
# ---------------------------------------------------------------------------case ${oratab_exist} in
Y)if [ -z $1 ]; thenSIDLIST=$(egrep -v -e '^$|#|\*' ${OTAB} | cut -f1 -d:)echo ""echo "List of Database Instances"printf "\n%-2s %-15s \n" "#" "ORACLE_SID"echo "-- ----------"PS3=$'\n'"Select a number from the list (1-n): "select sid in ${SIDLIST}; doecho ""if [ -n $sid ]; thenORACLE_SID=$sidload_env_headerload_db_envbreakfidoneelseload_env_headerif egrep -v '#|\*' ${OTAB} | grep -w "${1}:" >/dev/null; thenORACLE_SID=$1load_db_envelseecho " . PRIVATE_IP          = ${PRIVATE_IP}"echo " . PUBLIC_IP           = ${PUBLIC_IP}"echo " . HOSTNAME            = ${HOSTNAME}"echo "--------------------------------------------------------------------------------"echo "                       Database ENV is not set                                  "echo "                       Supplied ORACLE_SID ($1) not found in $OTAB.             "echo "                                                                                "echo " Run this to reload/setup the Database ENV: source /usr/local/bin/.set-env-db.sh"echo "--------------------------------------------------------------------------------"echo "================================================================================"echo " "fifi;;
*)load_env_headerecho " . PRIVATE_IP          = ${PRIVATE_IP}"echo " . PUBLIC_IP           = ${PUBLIC_IP}"echo " . HOSTNAME            = ${HOSTNAME}"echo "--------------------------------------------------------------------------------"echo "================================================================================"echo " ";;
esac

这个脚本里还有一个figlet命令,类似于banner:

$ figlet "Oracle LiveLabs"___                 _        _     _           _          _/ _ \ _ __ __ _  ___| | ___  | |   (_)_   _____| |    __ _| |__  ___
| | | | '__/ _` |/ __| |/ _ \ | |   | \ \ / / _ \ |   / _` | '_ \/ __|
| |_| | | | (_| | (__| |  __/ | |___| |\ V /  __/ |__| (_| | |_) \__ \\___/|_|  \__,_|\___|_|\___| |_____|_| \_/ \___|_____\__,_|_.__/|___/$ banner  "Oracle LiveLabs"#######  ######      #      #####   #        #######        #        ###  #     #  #######  #           #     ######    #####
#     #  #     #    # #    #     #  #        #              #         #   #     #  #        #          # #    #     #  #     #
#     #  #     #   #   #   #        #        #              #         #   #     #  #        #         #   #   #     #  #
#     #  ######   #     #  #        #        #####          #         #   #     #  #####    #        #     #  ######    #####
#     #  #   #    #######  #        #        #              #         #    #   #   #        #        #######  #     #        #
#     #  #    #   #     #  #     #  #        #              #         #     # #    #        #        #     #  #     #  #     #
#######  #     #  #     #   #####   #######  #######        #######  ###     #     #######  #######  #     #  ######    #####

接下来设置数据库参数:

connect / as sysdba
alter system set heat_map=ON scope=spfile;
alter system set sga_max_size=8G scope=spfile;
alter system set sga_target=8G scope=spfile;
alter system set db_keep_cache_size=3000M scope=spfile;
alter system set pga_aggregate_target=2500M scope=spfile;
alter system set inmemory_size=3300M scope=spfile;
alter system set inmemory_max_populate_servers=4 scope=spfile;
alter system set inmemory_virtual_columns=enable scope=spfile;
alter system set "_inmemory_64k_percent"=5 scope=spfile;
alter system set "_inmemory_small_segment_threshold"=0 scope=spfile;
alter system set "_optimizer_use_feedback"=FALSE scope=spfile;
alter system set "_imado_enable_coloptim"=FALSE scope=spfile;

查看隐含参数的脚本如下,详见MOS How To Query And Change The Oracle Hidden Parameters In Oracle 10g and Later (文档 ID 315631.1):

set lines 150
col parameter for a40
col "Session Value" for a20
col "Instance Value" for a20
SELECT a.ksppinm "Parameter", b.KSPPSTDF "Default Value",b.ksppstvl "Session Value", c.ksppstvl "Instance Value",decode(bitand(a.ksppiflg/256,1),1,'TRUE','FALSE') IS_SESSION_MODIFIABLE,decode(bitand(a.ksppiflg/65536,3),1,'IMMEDIATE',2,'DEFERRED',3,'IMMEDIATE','FALSE') IS_SYSTEM_MODIFIABLE
FROM   x$ksppi a,x$ksppcv b,x$ksppsv c
WHERE  a.indx = b.indx
AND    a.indx = c.indx
AND    a.ksppinm LIKE '/&1' escape '/'
/

以下是一些关键隐含参数的默认值和说明:

-- _inmemory_small_segment_threshold默认值为64K,表示小于此值的segment不会考虑发布到IMCS
-- _inmemory_64k_percent表示 in-memory area中元数据和数据的分配比例,默认为3比7
-- _imado_enable_coloptim没找到说明,
Parameter                                Default V Session Value        Instance Value       IS_SE IS_SYSTEM
---------------------------------------- --------- -------------------- -------------------- ----- ---------
_inmemory_small_segment_threshold        FALSE     65536                65536                FALSE IMMEDIATE
_inmemory_64k_percent                    FALSE     30                   30                   FALSE FALSE
_optimizer_use_feedback                  FALSE     TRUE                 TRUE                 TRUE  IMMEDIATE
_imado_enable_coloptim                   FALSE     TRUE                 TRUE                 TRUE  IMMEDIATE

_optimizer_use_feedback是11g引入的特性,详见以下文章:

  • Trivial Research on the Cardinality Feedback on 11gR2
  • Adaptive Optimisation ?
  • Hidden and Undocumented “Cardinality Feedback”

重启使其生效:

shutdown immediate
startup
exit

实验 3:设置 In-Memory Column Store

此实验的主要脚本执行序列如下,后面会详述:

@01_show_parms.sql
@02_show_sga.sql
@03_im_usage.sql
@04_im_alter_table.sql
@05_im_attributes.sql

每次实验前,都需要执行以下:

. ~/.set-env-db.sh CDB1

进入setup目录,登录数据库:

cd /home/oracle/labs/inmemory/setup
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

先去除inmemory属性,原文中少了SUPPLIER表:

alter table SSB.DATE_DIM no inmemory;
alter table SSB.PART no inmemory;
alter table SSB.CUSTOMER no inmemory;
alter table SSB.SUPPLIER no inmemory;
alter table SSB.LINEORDER modify partition PART_1996 no inmemory;
alter table SSB.LINEORDER modify partition PART_1998 no inmemory;
alter table SSB.LINEORDER modify partition PART_1995 no inmemory;
alter table SSB.LINEORDER modify partition PART_1997 no inmemory;
alter table SSB.LINEORDER modify partition PART_1994 no inmemory;

查看内存设置:

SQL> @01_show_parms.sql
Connected.
SQL>
SQL> -- Shows the SGA init.ora parameters
SQL>
SQL> show parameter sgaNAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
allow_group_access_to_sga            boolean     FALSE
lock_sga                             boolean     FALSE
pre_page_sga                         boolean     TRUE
sga_max_size                         big integer 8G
sga_min_size                         big integer 0
sga_target                           big integer 0
SQL>
SQL> show parameter db_keep_cache_sizeNAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_keep_cache_size                   big integer 3008M
SQL>
SQL> show parameter heat_mapNAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
heat_map                             string      ON
SQL>
SQL> show parameter inmemory_sizeNAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_size                        big integer 3312M
SQL>
SQL> set echo off

可以看到我们修改了以下的默认参数:

  • INMEMORY_SIZE由0改为3300M
  • HEAT_MAP由OFF改为ON
  • DB_KEEP_CACHE_SIZE由0改为3000M,以便行式内存和列式内存的性能差异。

查看SGA设置,SGA设置为8G,输出显示In-Memory Area已配置:

SQL> @02_show_sga.sql
Connected.
SQL> set numwidth 20
SQL>
SQL> -- Show SGA memory allocation
SQL>
SQL> show sgaTotal System Global Area           8589933480 bytes
Fixed Size                            9706408 bytes
Variable Size                       486539264 bytes
Database Buffers                   4613734400 bytes
Redo Buffers                          7069696 bytes
In-Memory Area                     3472883712 bytes
SQL>
SQL> set echo off

SGA 由固定大小、可变大小、数据库缓冲区和重做缓冲区组成。 由于我们设置了 INEMMORY_SIZE 参数,我们还可以看到在 SGA 中分配的 In-Memory Area。

In-Memory 区域被细分为两个池:一个 1MB 的池用于存储填充在 IM 列存储中的实际列格式数据,一个 64KB 的池用于存储有关填充在 IM 列存储中的对象的元数据。 V$INMEMORY_AREA 视图显示了在 IM 列存储中分配和使用的总内存。

SQL> @03_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS                          CON_ID
---------- -------------------- -------------------- -------------------------- --------------------
1MB POOL          3,252,682,752                    0 DONE                                          3
64KB POOL           201,326,592                    0 DONE                                          3SQL>
SQL> set echo off

可以看到这两个池的比例为95比5:

SQL> select 3252682752/(3252682752+201326592) from dual;3252682752/(3252682752+201326592)
---------------------------------.9417122040072859745

为SSB schema中的5张表设置inmemory属性:

SQL> @04_im_alter_table.sql
Connected.
SQL>
SQL> -- Enable tables for in-memory
SQL>
SQL> alter table LINEORDER inmemory;Table altered.SQL> alter table PART inmemory;Table altered.SQL> alter table CUSTOMER inmemory;Table altered.SQL> alter table SUPPLIER inmemory;Table altered.SQL> alter table DATE_DIM inmemory;Table altered.SQL>
SQL> set echo off

显示属性:

SQL> @05_im_attributes.sql
Connected.
SQL>
SQL> -- Show table attributes
SQL>
SQL> select table_name, NULL as partition_name, buffer_pool, compression, compress_for, inmemory,2         inmemory_priority, inmemory_distribute, inmemory_compression3  from   user_tables4  where  table_name in ('DATE_DIM','PART','SUPPLIER','CUSTOMER')5  UNION ALL6  select table_name, partition_name, buffer_pool, compression, compress_for, inmemory,7         inmemory_priority, inmemory_distribute, inmemory_compression8  from   user_tab_partitions9  where  table_name = 'LINEORDER';DISK                              INMEMORY   INMEMORY     INMEMORY
TABLE_NAME   PARTITION_NAME  BUFFER_POOL COMPRESSION COMPRESS_FOR INMEMORY PRIORITY   DISTRIBUTE   COMPRESSION
------------ --------------- ----------- ----------- ------------ -------- ---------- ------------ --------------
CUSTOMER                     KEEP        ENABLED     BASIC        ENABLED  NONE       AUTO         FOR QUERY LOW
DATE_DIM                     KEEP        ENABLED     BASIC        ENABLED  NONE       AUTO         FOR QUERY LOW
PART                         KEEP        ENABLED     BASIC        ENABLED  NONE       AUTO         FOR QUERY LOW
SUPPLIER                     KEEP        ENABLED     BASIC        ENABLED  NONE       AUTO         FOR QUERY LOW
LINEORDER    PART_1994       KEEP        ENABLED     BASIC        ENABLED  HIGH       AUTO         FOR QUERY LOW
LINEORDER    PART_1995       KEEP        ENABLED     BASIC        ENABLED  HIGH       AUTO         FOR QUERY LOW
LINEORDER    PART_1996       KEEP        ENABLED     BASIC        ENABLED  HIGH       AUTO         FOR QUERY LOW
LINEORDER    PART_1997       KEEP        ENABLED     BASIC        ENABLED  HIGH       AUTO         FOR QUERY LOW
LINEORDER    PART_1998       KEEP        ENABLED     BASIC        ENABLED  HIGH       AUTO         FOR QUERY LOW9 rows selected.SQL>
SQL> set echo off

通过全表扫描发布到IMCS:

SQL> @06_im_start_pop.sql
Connected.
SQL>
SQL> -- Access tables enabled for in-memory to start population
SQL>
SQL> select /*+ full(LINEORDER) noparallel(LINEORDER) */ count(*) from LINEORDER;COUNT(*)
--------------------41760941SQL> select /*+ full(PART) noparallel(PART) */ count(*) from PART;COUNT(*)
--------------------800000SQL> select /*+ full(CUSTOMER) noparallel(CUSTOMER) */ count(*) from CUSTOMER;COUNT(*)
--------------------300000SQL> select /*+ full(SUPPLIER) noparallel(SUPPLIER) */ count(*) from SUPPLIER;COUNT(*)
--------------------20000SQL> select /*+ full(DATE_DIM) noparallel(DATE_DIM) */ count(*) from DATE_DIM;COUNT(*)
--------------------2556SQL>
SQL> set echo off

注意 FULL 和 NOPARALLEL 提示。 他们可确保表数据也被读入定义的 KEEP 池。 这仅针对本实验进行,以便我们可以向您展示基于内存的数据库内存列格式与传统行格式的性能比较。 这不是启动 Database In-Memory 填充所必需的。

populate_wait是同步发布的PL/SQL过程,但此处也可以用于查询发布状态:

SQL> @07_populate_wait.sql
Connected.
SQL>
SQL> -- Show populate_wait query
SQL>
SQL> -- Return code:
SQL> --   -1 = POPULATE_TIMEOUT
SQL> --    0 = POPULATE_SUCCESS
SQL> --    1 = POPULATE_OUT_OF_MEMORY
SQL> --    2 = POPULATE_NO_INMEMORY_OBJECTS
SQL> --    3 = POPULATE_INMEMORY_SIZE_ZERO
SQL>
SQL> select dbms_inmemory_admin.populate_wait(priority=>'NONE',percentage=>100,timeout=>60) pop_status from dual;POP_STATUS
--------------------0SQL>
SQL> set echo off

确认发布已完成,并且没有内存不够的现象:

SQL> @08_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                09 rows selected.SQL>
SQL> set echo off

查看in-memory area的使用情况,数据部分已用了近70%:

SQL> @09_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS               CON_ID
---------- -------------------- -------------------- --------------- --------------------
1MB POOL          3,252,682,752        2,234,515,456 DONE                               3
64KB POOL           201,326,592            6,029,312 DONE                               3SQL>
SQL> set echo off

实验 4:查询In-Memory Column Store

此实验的主要脚本执行序列如下,后面会详述:

@01_im_query_stats.sql
@02_buffer_query_stats.sql
@03_single_key_im.sql
@04_single_key_buffer.sql
@05_index_comparison.sql
@06_storage_index.sql
@07_multi_preds.sql

每次实验前,都需要执行以下:

. ~/.set-env-db.sh CDB1

进入queries目录,登录数据库:

cd /home/oracle/labs/inmemory/queries
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

先来看In-Memory全表扫描:

SQL> @01_im_query_stats.sql
-- 耗时
Elapsed: 00:00:00.02
-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |  4376 (100)|          |       |       |
|   1 |  SORT AGGREGATE              |           |     1 |     9 |            |          |       |       |
|   2 |   PARTITION RANGE ALL        |           |    41M|   358M|  4376  (27)| 00:00:01 |     1 |     5 |
|   3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|   358M|  4376  (27)| 00:00:01 |     1 |     5 |
------------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                             23
IM scan CUs columns accessed                                        156
IM scan CUs memcompress for query low                                78
IM scan CUs pcode aggregation pushdown                              156
IM scan rows                                                   41760941
IM scan rows pcode aggregated                                  41760941
IM scan rows projected                                               78
IM scan rows valid                                             41760941
physical reads                                                       79
session logical reads                                            323922
session logical reads - IM                                       315483
session pga memory                                             19335472
table scans (IM)                                                      513 rows selected.

再来看buffer cache中的全表扫描(通过/*+ NO_INMEMORY */提示禁用了In-Memory),此查询要多执行几次,以保证会话统计信息中没有物理读。结果表明慢了近200倍:

SQL>
-- 耗时
Elapsed: 00:00:03.94-- 执行计划
--------------------------------------------------------------------------------------------------
| Id  | Operation            | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |           |       |       | 86830 (100)|          |       |       |
|   1 |  SORT AGGREGATE      |           |     1 |     9 |            |          |       |       |
|   2 |   PARTITION RANGE ALL|           |    41M|   358M| 86830   (2)| 00:00:04 |     1 |     5 |
|   3 |    TABLE ACCESS FULL | LINEORDER |    41M|   358M| 86830   (2)| 00:00:04 |     1 |     5 |
---------------------------------------------------------------------------------------------------- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            405
IM scan segments disk                                                 5
session logical reads                                            320529
session pga memory                                             19269936

在本例中,为什么列式内存比行式内存快很多?

IM 列存储只需扫描两列 - LO_ORDTOTALPRICE 和 LO_QUANTITY - 而行存储必须扫描每一行中的所有列,直到它到达 LO_ORDTOTALPRICE 和 LO_QUANTITY 列。 IM 列存储还受益于内存中数据压缩,因此扫描的数据量要少得多。最后,列格式可以利用 SIMD 矢量处理(单指令处理多个数据值)。 SIMD 向量处理不是一次评估列中的每个条目,而是允许在单个 CPU 指令中一起评估一组列值。

执行计划显示优化器选择了内存扫描,但要确认使用了 IM 列存储,我们需要检查会话级别的统计信息。请注意,在内存查询中显示了几个 IM 统计信息(对于本实验,我们只显示了一些关键统计信息——还有更多!)。我们现在唯一真正感兴趣的是“IM scan rows”。

IM scan rows表示扫描的内存行数。

当我们的查询对 LINEORDER 表进行全表扫描时,该会话统计显示我们从 IM 列存储中扫描了大约 4100 万行。 请注意,在第二个缓冲区缓存查询中,没有显示该统计信息。 只有一个内存统计显示,“IM scan segments disk”,值为 1。这意味着即使 LINEORDER 表在 IM 列存储(IM 段)中,我们实际上从列存储之外扫描该段缓冲区缓存。 由于我们完全缓存了 KEEP 池中的表,因此我们正在进行内存与内存比较,在这种情况下,我们可以验证查询没有物理 IO(如果显示少量物理 IO,则尝试再次运行它以确保 它完全缓存在 KEEP 池中)。

再来看单个值查询,理论上IMCS是不适合的:

SQL> @03_single_key_im.sql
-- 耗时
Elapsed: 00:00:00.01-- 执行计划
---------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |       |       |  3570 (100)|          |       |       |
|   1 |  PARTITION RANGE ALL        |           |     4 |    68 |  3570  (10)| 00:00:01 |     1 |     5 |
|*  2 |   TABLE ACCESS INMEMORY FULL| LINEORDER |     4 |    68 |  3570  (10)| 00:00:01 |     1 |     5 |
---------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - inmemory("LO_ORDERKEY"=5000000)filter("LO_ORDERKEY"=5000000)

请注意,在执行计划的谓词信息中,您会看到“inmemory”和“filter”。 这表明过滤谓词(即“LO_ORDERKEY”=5000000)被“推送”到 LINEORDER 表的扫描中,而不必在检索到值后进行评估。 这是 Database In-Memory 加快查询速度的重要方式之一。

然后在行式内存中运行同样的查询,此时还没有用到索引。和列式内存比,性能差243倍:

SQL>
-- 耗时
Elapsed: 00:00:02.43-- 执行计划
-------------------------------------------------------------------------------------------------
| Id  | Operation           | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |       |       | 86485 (100)|          |       |       |
|   1 |  PARTITION RANGE ALL|           |     4 |    68 | 86485   (1)| 00:00:04 |     1 |     5 |
|*  2 |   TABLE ACCESS FULL | LINEORDER |     4 |    68 | 86485   (1)| 00:00:04 |     1 |     5 |
-------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("LO_ORDERKEY"=5000000)

请注意,在执行计划的谓词信息中,您只能看到“过滤器”。 这表明过滤谓词(即“LO_ORDERKEY”=5000000)是在检索到值之后评估的。 而Database In-Memory却可以在扫描数据期间进行过滤。

行式内存加索引的效果如何呢?我们启用了之前隐藏的索引:

SQL> @05_index_comparison.sql-- 耗时
Elapsed: 00:00:00.01-- 执行计划
---------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name         | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |              |       |       |    12 (100)|          |       |       |
|   1 |  PARTITION RANGE ALL                       |              |     4 |    68 |    12   (0)| 00:00:01 |     1 |     5 |
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| LINEORDER    |     4 |    68 |    12   (0)| 00:00:01 |     1 |     5 |
|*  3 |    INDEX RANGE SCAN                        | LINEORDER_I2 |     4 |       |    11   (0)| 00:00:01 |     1 |     5 |
---------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - access("LO_ORDERKEY"=5000000)

此时行式内存和列式内存的性能基本相同。请注意,在执行计划中,对 LINEORDER_I2 索引执行了 INDEX RANGE SCAN。 这是 Oracle 实施 Database In-Memory 的方式的另一大好处。 优化器基于成本能够确定访问数据的最有效方式。 在此示例中,如果有适当的索引可用,优化器决定使用该索引更有效。 这就是无需更改应用程序 SQL 即可使用 Database In-Memory 的原因,也是 Database In-Memory 可用于混合工作负载环境(即同时使用事务和分析)的原因。

如果您没有优化器可以使用的索引,但您已经在 IM 列存储中填充了数据,该怎么办。 性能会受到影响吗? Database In-Memory 的另一个特性称为 In-Memory Storage Indexes。 我们将重复第 3 步中的查询,但这次我们将包含更多信息,看看我们是否能弄清楚幕后发生了什么。

SQL> @06_storage_index.sql
-- 耗时,和查询3一样-- 执行计划,和查询3一样-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                              4
IM scan CUs columns accessed                                          7
IM scan CUs memcompress for query low                                78
IM scan CUs pruned                                                   73
IM scan rows                                                   41760941
IM scan rows projected                                                1
IM scan rows valid                                              2675664
IM scan segments minmax eligible                                     78
session logical reads                                            315634
session logical reads - IM                                       315483
session pga memory                                             18221360
table scans (IM)                                                      512 rows selected.

这次我们包括了查询的会话统计信息。 注意两个关键统计数据。 第一个是“IM scan CUs memcompress for query low”,此处为78。 这告诉我们数据填充到了多少个 IMCU。 第二个重要的统计数据是“IM scan CUs pruned”,此处为73。 请注意,这个数字几乎与 IMCU 的总数一样大。 这意味着 Database In-Memory 能够避免扫描绝大部分的数据。 这是因为在填充时为每个 IMCU 中的每组列值创建了内存中存储索引,其中包含 MIN 和 MAX 值。 在扫描期间,这些 MIN 和 MAX 值可以与过滤谓词进行比较,因此可以略过不必扫描的列数据,从而提高性能。 毕竟,做某事最快的方法就是完全不做。

下一个是多谓词查询。传统上,您会创建一个多列索引。 In-Memory能与之抗衡吗?:

SQL> @07_multi_preds.sql
-- 耗时
Elapsed: 00:00:00.04-- 执行计划
---------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |       |       |  3329 (100)|          |       |       |
|   1 |  PARTITION RANGE ALL        |           |     6 |   264 |  3329   (4)| 00:00:01 |     1 |     5 |
|*  2 |   TABLE ACCESS INMEMORY FULL| LINEORDER |     6 |   264 |  3329   (4)| 00:00:01 |     1 |     5 |
---------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - inmemory(("LO_CUSTKEY"=5641 AND "LO_SHIPMODE"='SHIP' AND "LO_ORDERPRIORITY"='5-LOW'))filter(("LO_CUSTKEY"=5641 AND "LO_SHIPMODE"='SHIP' AND "LO_ORDERPRIORITY"='5-LOW'))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                              6
IM scan CUs columns accessed                                        169
IM scan CUs memcompress for query low                                78
IM scan rows                                                   41760941
IM scan rows projected                                               13
IM scan rows valid                                             41760941
IM scan segments minmax eligible                                     78
physical reads                                                        4
session logical reads                                            315997
session logical reads - IM                                       315483
session pga memory                                             18417968
table scans (IM)                                                      512 rows selected.

在此示例中,您可以在 Predicate Information 部分看到多个过滤谓词包含在“inmemory”函数中。 Database In-Memory 不限于仅将单个谓词推送到扫描中。 还有另一个重要的统计数据可用于衡量通过将谓词推送到扫描中节省了多少工作。 注意统计“IM scan rows projected”。 该值为 13,这正是查询返回的行数。 该统计数据表明,即使我们扫描了 4100 万行,我们也只返回了 13 行。 这是 Database In-Memory 比行存储快得多的另一个原因。
更为复杂的查询:

SQL>
-- 耗时
Elapsed: 00:00:00.05-- 执行计划
---------------------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |           |       |       | 12736 (100)|          |       |       |
|   1 |  PARTITION RANGE ALL              |           |     7 |    84 |  4008  (20)| 00:00:01 |     1 |     5 |
|*  2 |   TABLE ACCESS INMEMORY FULL      | LINEORDER |     7 |    84 |  4008  (20)| 00:00:01 |     1 |     5 |
|   3 |    SORT AGGREGATE                 |           |     1 |    25 |            |          |       |       |
|   4 |     PARTITION RANGE ALL           |           |    75 |  1875 |  4537  (30)| 00:00:01 |     1 |     5 |
|*  5 |      TABLE ACCESS INMEMORY FULL   | LINEORDER |    75 |  1875 |  4537  (30)| 00:00:01 |     1 |     5 |
|   6 |       SORT AGGREGATE              |           |     1 |     8 |            |          |       |       |
|   7 |        PARTITION RANGE ALL        |           |    33M|   254M|  4192  (24)| 00:00:01 |     1 |     5 |
|*  8 |         TABLE ACCESS INMEMORY FULL| LINEORDER |    33M|   254M|  4192  (24)| 00:00:01 |     1 |     5 |
---------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - inmemory("LO_REVENUE"=)filter("LO_REVENUE"=)5 - inmemory(("LO_SHIPMODE" LIKE 'TRUCK%' AND "LO_DISCOUNT"<=5 AND "LO_DISCOUNT">=2 AND"LO_SUPPLYCOST"=))filter(("LO_SHIPMODE" LIKE 'TRUCK%' AND "LO_DISCOUNT"<=5 AND "LO_DISCOUNT">=2 AND"LO_SUPPLYCOST"=))8 - inmemory("LO_QUANTITY">10)filter("LO_QUANTITY">10)-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                              8
IM scan CUs columns accessed                                        388
IM scan CUs memcompress for query low                               234
IM scan CUs pcode aggregation pushdown                               81
IM scan CUs pruned                                                   29
IM scan rows                                                  125282823
IM scan rows pcode aggregated                                  33408482
IM scan rows projected                                               85
IM scan rows valid                                            109859292
IM scan segments minmax eligible                                    234
physical reads                                                        2
session logical reads                                            946622
session logical reads - IM                                       946449
session pga memory                                             18286896
table scans (IM)                                                     1515 rows selected.

即使有所有这些复杂的谓词,优化器还是选择了In-Memory查询,这表明对于大型扫描操作,这是最有效的方法。

实验小节:
在本实验中,您有机会通过针对超过 4100 万行的表(即 LINEORDER 表,该表驻留在 IM 列存储和缓冲区缓存 KEEP 池中)运行查询来尝试 Oracle 宣称的In-Memory性能。 从非常简单的聚合到具有多列和过滤谓词的更复杂查询,IM 列存储能够胜过缓冲区缓存查询。 请记住,这两组查询都完全在内存中执行,因此这是一个令人印象深刻的改进。

由于 Oracle 独特的内存中列格式允许我们只扫描我们需要的列并充分利用 SIMD 矢量处理,这些显着的性能改进是可能的。 我们还从新的内存存储索引中获得了一些帮助,这使我们能够跳过不必要的数据。 请记住,使用 IM 列存储,每列都有一个为您自动维护的存储索引。

实验 5:连接和聚合

到目前为止,我们一直专注于只扫描一个表的查询,即 LINEORDER 表。 让我们扩大考察的范围,包括连接和并行执行。 此部分执行一系列查询,这些查询以事实表LINEORDER 和一个或多个维度表之间的单个联接开始,最多可进行 5 个表联接。 查询将在缓冲区缓存和列存储中执行,以演示列存储可以提高查询性能的不同方式,而不仅仅是以列格式扫描数据的基本性能优势。

此实验的主要脚本执行序列如下,后面会详述:

@01_join_im.sql
@02_join_buffer.sql
@03_3join_im.sql
@04_3join_buffer.sql
@05_join_nl_im.sql
@06_vgb_im.sql
@07_novgb_im.sql
@08_vgb_buffer.sql
@09_novgb_buffer.sql

每次实验前,都需要执行以下:

. ~/.set-env-db.sh CDB1

进入joins-aggr目录,登录数据库:

cd /home/oracle/labs/inmemory/joins-aggr
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

先看一个“What-if”查询:

SQL> @01_join_im.sql
-- 耗时
Elapsed: 00:00:00.04-- 执行计划
------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |           |       |       |  4595 (100)|          |       |       |
|   1 |  SORT AGGREGATE                |           |     1 |    47 |            |          |       |       |
|*  2 |   HASH JOIN                    |           |  2085 | 97995 |  4595  (31)| 00:00:01 |       |       |
|   3 |    JOIN FILTER CREATE          | :BF0001   |     1 |    27 |     1   (0)| 00:00:01 |       |       |
|   4 |     PART JOIN FILTER CREATE    | :BF0000   |     1 |    27 |     1   (0)| 00:00:01 |       |       |
|*  5 |      TABLE ACCESS INMEMORY FULL| DATE_DIM  |     1 |    27 |     1   (0)| 00:00:01 |       |       |
|   6 |    JOIN FILTER USE             | :BF0001   |  3492K|    66M|  4575  (30)| 00:00:01 |       |       |
|   7 |     PARTITION RANGE JOIN-FILTER|           |  3492K|    66M|  4575  (30)| 00:00:01 |:BF0000|:BF0000|
|*  8 |      TABLE ACCESS INMEMORY FULL| LINEORDER |  3492K|    66M|  4575  (30)| 00:00:01 |:BF0000|:BF0000|
------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")5 - inmemory("D"."D_DATE"='December 24, 1996')filter("D"."D_DATE"='December 24, 1996')8 - inmemory(("L"."LO_DISCOUNT"<=3 AND "L"."LO_QUANTITY"<24 AND "L"."LO_DISCOUNT">=2 ANDSYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_ORDERDATE")))filter(("L"."LO_DISCOUNT"<=3 AND "L"."LO_QUANTITY"<24 AND "L"."LO_DISCOUNT">=2 ANDSYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_ORDERDATE")))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                              7
IM scan CUs columns accessed                                         70
IM scan CUs memcompress for query low                                18
IM scan CUs pcode aggregation pushdown                               17
IM scan rows                                                    9128918
IM scan rows pcode aggregated                                      2131
IM scan rows projected                                               17
IM scan rows valid                                              9128918
IM scan segments minmax eligible                                     18
session logical reads                                             69667
session logical reads - IM                                        68987
session pga memory                                             18745648
table scans (IM)                                                      213 rows selected.

Database In-Memory 使用连接执行查询没有问题,实际上可以通过利用布隆过滤器来优化散列连接。 在执行计划中很容易识别布隆过滤器。 它们将出现在两个地方,创建时(即 JOIN FILTER CREATE)和应用时(即 JOIN FILTER USE)。 查看上面计划中的 ID 3 和 ID 6。 您还可以通过查看计划下的谓词信息来了解用于构建 Bloom 过滤器的连接条件。

您可能还注意到在第 4 行使用了另一个布隆过滤器。这不是 Database In-Memory 特性,而只是 Oracle 数据库优化对构成 LINEORDER 表的分区的访问。 这里的一个要点是,使用 Database In-Memory 并不妨碍使用其他 Oracle Database 特性

在buffer cache中的执行,慢了20倍:

SQL> @02_join_buffer.sql
-- 耗时
Elapsed: 00:00:00.80-- 执行计划
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |           |       |       | 87113 (100)|          |       |       |
|   1 |  SORT AGGREGATE               |           |     1 |    44 |            |          |       |       |
|*  2 |   HASH JOIN                   |           | 24932 |  1071K| 87113   (2)| 00:00:04 |       |       |
|   3 |    PART JOIN FILTER CREATE    | :BF0000   |     1 |    27 |     7   (0)| 00:00:01 |       |       |
|*  4 |     TABLE ACCESS FULL         | DATE_DIM  |     1 |    27 |     7   (0)| 00:00:01 |       |       |
|   5 |    PARTITION RANGE JOIN-FILTER|           |    41M|   677M| 86876   (2)| 00:00:04 |:BF0000|:BF0000|
|   6 |     TABLE ACCESS FULL         | LINEORDER |    41M|   677M| 86876   (2)| 00:00:04 |:BF0000|:BF0000|
-----------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")4 - filter("D"."D_DATE"='December 24, 1996')-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                             84
IM scan segments disk                                                 2
session logical reads                                             69106
session pga memory                                             19269936

您可能会注意到我们添加了一个提示来指定 NO_INMEMORY。 这是告诉优化器不要使用 IM 列存储的简单方法。 您可能还会注意到还有一个 NO_VECTOR_TRANSFORM 提示。 启用 Database In-Memory 时可以使用矢量变换,我们将在本实验的后面部分介绍它的优点。 目前,我们已禁用它,以便更容易地将此执行计划与上一步中的执行计划进行比较。

更复杂的,3表的联结和聚合:

SQL>
-- 耗时
Elapsed: 00:00:00.23-- 执行计划
----------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |           |       |       |  5280 (100)|          |       |       |
|   1 |  HASH GROUP BY                     |           |  1000 | 77000 |  5280  (38)| 00:00:01 |       |       |
|*  2 |   HASH JOIN                        |           | 98430 |  7401K|  5275  (38)| 00:00:01 |       |       |
|   3 |    JOIN FILTER CREATE              | :BF0001   |   365 |  4380 |     1   (0)| 00:00:01 |       |       |
|   4 |     PART JOIN FILTER CREATE        | :BF0000   |   365 |  4380 |     1   (0)| 00:00:01 |       |       |
|*  5 |      TABLE ACCESS INMEMORY FULL    | DATE_DIM  |   365 |  4380 |     1   (0)| 00:00:01 |       |       |
|*  6 |    HASH JOIN                       |           |   451K|    28M|  5272  (38)| 00:00:01 |       |       |
|   7 |     JOIN FILTER CREATE             | :BF0002   |  4102 | 73836 |     4  (25)| 00:00:01 |       |       |
|*  8 |      TABLE ACCESS INMEMORY FULL    | SUPPLIER  |  4102 | 73836 |     4  (25)| 00:00:01 |       |       |
|*  9 |     HASH JOIN                      |           |  2216K|    99M|  5256  (38)| 00:00:01 |       |       |
|  10 |      JOIN FILTER CREATE            | :BF0003   | 31882 |   716K|    97  (27)| 00:00:01 |       |       |
|* 11 |       TABLE ACCESS INMEMORY FULL   | PART      | 31882 |   716K|    97  (27)| 00:00:01 |       |       |
|  12 |      JOIN FILTER USE               | :BF0001   |    41M|   955M|  4928  (35)| 00:00:01 |       |       |
|  13 |       JOIN FILTER USE              | :BF0002   |    41M|   955M|  4928  (35)| 00:00:01 |       |       |
|  14 |        JOIN FILTER USE             | :BF0003   |    41M|   955M|  4928  (35)| 00:00:01 |       |       |
|  15 |         PARTITION RANGE JOIN-FILTER|           |    41M|   955M|  4928  (35)| 00:00:01 |:BF0000|:BF0000|
|* 16 |          TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|   955M|  4928  (35)| 00:00:01 |:BF0000|:BF0000|
----------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")5 - inmemory("D"."D_YEAR"=1997)filter("D"."D_YEAR"=1997)6 - access("L"."LO_SUPPKEY"="S"."S_SUPPKEY")8 - inmemory("S"."S_REGION"='AMERICA')filter("S"."S_REGION"='AMERICA')9 - access("L"."LO_PARTKEY"="P"."P_PARTKEY")11 - inmemory("P"."P_CATEGORY"='MFGR#12')filter("P"."P_CATEGORY"='MFGR#12')16 - inmemory(SYS_OP_BLOOM_FILTER_LIST(SYS_OP_BLOOM_FILTER(:BF0003,"L"."LO_PARTKEY"),SYS_OP_BLOOM_FILTER(:BF0002,"L"."LO_SUPPKEY"),SYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_ORDERDATE")))filter(SYS_OP_BLOOM_FILTER_LIST(SYS_OP_BLOOM_FILTER(:BF0003,"L"."LO_PARTKEY"),SYS_OP_BLOOM_FILTER(:BF0002,"L"."LO_SUPPKEY"),SYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_ORDERDATE")))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                             26
IM scan CUs columns accessed                                         78
IM scan CUs memcompress for query low                                21
IM scan rows                                                    9920979
IM scan rows projected                                           259319
IM scan rows valid                                              9920979
IM scan segments minmax eligible                                     21
session logical reads                                             76259
session logical reads - IM                                        75941
session pga memory                                             19466544
table scans (IM)                                                      411 rows selected.

在此查询中,已创建三个 Bloom 过滤器并将其应用于 LINEORDER 表的扫描,一个用于连接 DATE_DIM 表,一个用于连接 PART 表,一个用于连接 SUPPLIER 表。当一个连接通常一次只涉及两个表时,Oracle 如何应用三个布隆过滤器?

这就是 Oracle 30 多年的数据库创新发挥作用的地方。通过将列存储嵌入到 Oracle 数据库中,我们可以利用已添加到数据库中的所有优化。在这种情况下,优化器已使用称为“swap_join_inputs”的优化从其典型的左深度树执行切换到右深度树执行计划。这对 IM 列存储意味着我们能够通过在扫描“事实”表中的必要列之前扫描三个“维度”表来生成多个布隆过滤器,这意味着我们能够在扫描时去除行而不是等待Join来执行它。

在buffer cache执行上一个查询,慢了4倍:

SQL>
-- 耗时
Elapsed: 00:00:01.00-- 执行计划
-------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |           |       |       | 89164 (100)|          |       |       |
|   1 |  HASH GROUP BY                  |           |  1000 | 77000 | 89164   (2)| 00:00:04 |       |       |
|*  2 |   HASH JOIN                     |           | 98430 |  7401K| 89159   (2)| 00:00:04 |       |       |
|   3 |    PART JOIN FILTER CREATE      | :BF0000   |   365 |  4380 |     7   (0)| 00:00:01 |       |       |
|*  4 |     TABLE ACCESS FULL           | DATE_DIM  |   365 |  4380 |     7   (0)| 00:00:01 |       |       |
|*  5 |    HASH JOIN                    |           |   451K|    28M| 89149   (2)| 00:00:04 |       |       |
|*  6 |     TABLE ACCESS FULL           | SUPPLIER  |  4102 | 73836 |    70   (2)| 00:00:01 |       |       |
|*  7 |     HASH JOIN                   |           |  2216K|    99M| 89067   (2)| 00:00:04 |       |       |
|*  8 |      TABLE ACCESS FULL          | PART      | 31882 |   716K|  1915   (2)| 00:00:01 |       |       |
|   9 |      PARTITION RANGE JOIN-FILTER|           |    41M|   955M| 86922   (2)| 00:00:04 |:BF0000|:BF0000|
|  10 |       TABLE ACCESS FULL         | LINEORDER |    41M|   955M| 86922   (2)| 00:00:04 |:BF0000|:BF0000|
-------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")4 - filter("D"."D_YEAR"=1997)5 - access("L"."LO_SUPPKEY"="S"."S_SUPPKEY")6 - filter("S"."S_REGION"='AMERICA')7 - access("L"."LO_PARTKEY"="P"."P_PARTKEY")8 - filter("P"."P_CATEGORY"='MFGR#12')-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            126
IM scan segments disk                                                 4
session logical reads                                             80154
session pga memory                                             20777264

到目前为止,我们只看到了与内存查询一起使用的哈希连接。 虽然哈希联接确实是对 Database In-Memory 的进一步优化,并且它能够使用 Bloom 过滤器将联接有效地执行为扫描和过滤操作,但是嵌套循环联接呢? Database In-Memory 是否可以使用嵌套循环连接? 也许一个表不在内存中,或者索引访问的成本会更低。 让我们看看它是如何工作的。此查询中,我们通过提示启用了隐藏的索引。

SQL> 05_join_nl_im.sql
-- 耗时
Elapsed: 00:00:00.06-- 执行计划
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name         | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |              |       |       |  6134 (100)|          |       |       |
|   1 |  SORT AGGREGATE                     |              |     1 |    44 |            |          |       |       |
|   2 |   NESTED LOOPS                      |              | 24932 |  1071K|  6134   (1)| 00:00:01 |       |       |
|   3 |    NESTED LOOPS                     |              | 24932 |  1071K|  6134   (1)| 00:00:01 |       |       |
|*  4 |     TABLE ACCESS INMEMORY FULL      | DATE_DIM     |     1 |    27 |     1   (0)| 00:00:01 |       |       |
|   5 |     PARTITION RANGE ITERATOR        |              | 24932 |       |    65   (0)| 00:00:01 |   KEY |   KEY |
|*  6 |      INDEX RANGE SCAN               | LINEORDER_I1 | 24932 |       |    65   (0)| 00:00:01 |   KEY |   KEY |
|   7 |    TABLE ACCESS BY LOCAL INDEX ROWID| LINEORDER    | 24932 |   413K|  6133   (1)| 00:00:01 |     1 |     1 |
--------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------4 - inmemory("D"."D_DATE"='December 24, 1996')filter("D"."D_DATE"='December 24, 1996')6 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")Note
------ this is an adaptive plan

请注意,我们已经告诉优化器它可以使用不可见的索引,并且我们添加了一个可以在 LINEORDER 表上使用的索引提示。 这导致优化器选择执行嵌套循环连接,首先访问内存中的 DATE_DIM 表,然后通过索引访问 LINEORDER 表。 在此示例中,访问 IM 列存储中的 LINEORDER 表的成本较低,但我们想向您展示优化器在使用内存时可以选择不同的连接类型。 如果您喜欢冒险,您可以编辑脚本并删除索引提示。 不用担心,这是您自己的环境,不会影响其他人。 如果您随后再次运行查询,您可以比较通过使用嵌套循环连接的索引访问数据的成本。 要记住的是优化器能够选择成本最低的方法来运行查询,无论是否访问内存中的对象。

确实,本例使用Nested Loop联结确实比哈希Join快些。

现在让我们将注意力转向更多 OLAP 风格的“What-if”查询。

Oracle 引入了一种新的优化器转换,称为向量转换。这也称为 In-Memory Aggregation,并产生一个新的 group by 方法,称为 Vector Group By。这种转换是一个两部分的过程,与星型转换的过程没有什么不同。

原理就不翻译了:

First, the dimension tables are scanned and any WHERE clause predicates are applied. A new data structure called a key vector is created based on the results of these scans. The key vector is similar to a Bloom filter as it allows the join predicates to be applied as additional filter predicates during the scan of the fact table, but it also enables us to conduct the group by or aggregation during the scan of the fact table instead of having to do it afterwards.

The second part of the execution plan sees the results of the fact table scan being joined back to the temporary tables created as part of the scan of the dimension tables, that is defined by the lines that start with LOAD AS SELECT. These temporary tables contain the payload columns (columns needed in the select list) from the dimension table(s). In Release 12.2 and above these tables are now pure in-memory tables as evidenced by the addition of the (CURSOR DURATION MEMORY) phrase that is appended to the LOAD AS SELECT phrases. The combination of these two features dramatically improves the efficiency of a multiple table join with complex aggregations. Both features are visible in the execution plan of our queries.

来看下Vector Group By的效果:

SQL> @06_vgb_im.sql
-- 耗时
Elapsed: 00:00:00.67-- 执行计划
--------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name                      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |                           |       |       |  5619 (100)|          |       |       |
|   1 |  TEMP TABLE TRANSFORMATION               |                           |       |       |            |          |       |       |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D663D_53FD65 |       |       |            |          |       |       |
|   3 |    HASH GROUP BY                         |                           |     7 |   112 |     2  (50)| 00:00:01 |       |       |
|   4 |     KEY VECTOR CREATE BUFFERED           | :KV0000                   |     7 |   112 |     1   (0)| 00:00:01 |       |       |
|   5 |      TABLE ACCESS INMEMORY FULL          | DATE_DIM                  |  2556 | 30672 |     1   (0)| 00:00:01 |       |       |
|   6 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D663A_53FD65 |       |       |            |          |       |       |
|   7 |    HASH GROUP BY                         |                           |     1 |     9 |   120  (41)| 00:00:01 |       |       |
|   8 |     KEY VECTOR CREATE BUFFERED           | :KV0001                   |     1 |     9 |    80  (12)| 00:00:01 |       |       |
|   9 |      TABLE ACCESS INMEMORY FULL          | PART                      |   800K|  3906K|    77   (8)| 00:00:01 |       |       |
|  10 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D663B_53FD65 |       |       |            |          |       |       |
|  11 |    HASH GROUP BY                         |                           |     1 |    22 |     5  (40)| 00:00:01 |       |       |
|  12 |     KEY VECTOR CREATE BUFFERED           | :KV0002                   |     1 |    22 |     4  (25)| 00:00:01 |       |       |
|* 13 |      TABLE ACCESS INMEMORY FULL          | SUPPLIER                  |  4102 | 73836 |     4  (25)| 00:00:01 |       |       |
|  14 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D663C_53FD65 |       |       |            |          |       |       |
|  15 |    HASH GROUP BY                         |                           |    25 |   950 |    45  (32)| 00:00:01 |       |       |
|  16 |     KEY VECTOR CREATE BUFFERED           | :KV0003                   |    25 |   950 |    41  (25)| 00:00:01 |       |       |
|* 17 |      TABLE ACCESS INMEMORY FULL          | CUSTOMER                  | 59761 |  1984K|    41  (25)| 00:00:01 |       |       |
|  18 |   SORT GROUP BY                          |                           |    62 |  6510 |  5448  (41)| 00:00:01 |       |       |
|* 19 |    HASH JOIN                             |                           |    62 |  6510 |  5447  (41)| 00:00:01 |       |       |
|* 20 |     HASH JOIN                            |                           |    62 |  4712 |  5445  (41)| 00:00:01 |       |       |
|  21 |      MERGE JOIN CARTESIAN                |                           |     7 |   329 |     6   (0)| 00:00:01 |       |       |
|  22 |       MERGE JOIN CARTESIAN               |                           |     1 |    31 |     4   (0)| 00:00:01 |       |       |
|  23 |        TABLE ACCESS FULL                 | SYS_TEMP_0FD9D663A_53FD65 |     1 |     9 |     2   (0)| 00:00:01 |       |       |
|  24 |        BUFFER SORT                       |                           |     1 |    22 |     2   (0)| 00:00:01 |       |       |
|  25 |         TABLE ACCESS FULL                | SYS_TEMP_0FD9D663B_53FD65 |     1 |    22 |     2   (0)| 00:00:01 |       |       |
|  26 |       BUFFER SORT                        |                           |     7 |   112 |     4   (0)| 00:00:01 |       |       |
|  27 |        TABLE ACCESS FULL                 | SYS_TEMP_0FD9D663D_53FD65 |     7 |   112 |     2   (0)| 00:00:01 |       |       |
|  28 |      VIEW                                | VW_VT_80F21617            |    62 |  1798 |  5439  (41)| 00:00:01 |       |       |
|  29 |       VECTOR GROUP BY                    |                           |    62 |  3100 |  5439  (41)| 00:00:01 |       |       |
|  30 |        HASH GROUP BY                     |                           |    62 |  3100 |  5439  (41)| 00:00:01 |       |       |
|  31 |         KEY VECTOR USE                   | :KV0000                   |  2535K|   120M|  5437  (41)| 00:00:01 |       |       |
|  32 |          KEY VECTOR USE                  | :KV0001                   |  2535K|   111M|  5436  (41)| 00:00:01 |       |       |
|  33 |           KEY VECTOR USE                 | :KV0003                   |  2535K|   101M|  5436  (41)| 00:00:01 |       |       |
|  34 |            KEY VECTOR USE                | :KV0002                   |  8510K|   308M|  5436  (41)| 00:00:01 |       |       |
|  35 |             PARTITION RANGE ITERATOR     |                           |    41M|  1354M|  5434  (41)| 00:00:01 |:KV0000|:KV0000|
|* 36 |              TABLE ACCESS INMEMORY FULL  | LINEORDER                 |    41M|  1354M|  5434  (41)| 00:00:01 |:KV0000|:KV0000|
|  37 |     TABLE ACCESS FULL                    | SYS_TEMP_0FD9D663C_53FD65 |    25 |   725 |     2   (0)| 00:00:01 |       |       |
--------------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------13 - inmemory("S"."S_REGION"='AMERICA')filter("S"."S_REGION"='AMERICA')17 - inmemory("C"."C_REGION"='AMERICA')filter("C"."C_REGION"='AMERICA')19 - access("ITEM_14"=INTERNAL_FUNCTION("C0"))20 - access("ITEM_12"=INTERNAL_FUNCTION("C0") AND "ITEM_13"=INTERNAL_FUNCTION("C0") AND "ITEM_15"=INTERNAL_FUNCTION("C0"))36 - inmemory((SYS_OP_KEY_VECTOR_FILTER("L"."LO_SUPPKEY",:KV0002) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_CUSTKEY",:KV0003)AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_PARTKEY",:KV0001) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_ORDERDATE",:KV0000)))filter((SYS_OP_KEY_VECTOR_FILTER("L"."LO_SUPPKEY",:KV0002) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_CUSTKEY",:KV0003) ANDSYS_OP_KEY_VECTOR_FILTER("L"."LO_PARTKEY",:KV0001) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_ORDERDATE",:KV0000)))Note
------ vector transformation used for this statement

我们的查询现在更加复杂,如果您仔细查看执行计划,您将看到:KV000n 结构的创建和使用,这些结构是关键向量以及 Vector Group By 操作。

如果没有Vector Group By,性能如何?优化器选择了布隆过滤器,性能慢了2倍。

SQL>
-- 耗时
Elapsed: 00:00:01.40-- 执行计划
------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |           |       |       |       | 44344 (100)|          |       |       |
|   1 |  SORT GROUP BY                     |           |   124 | 12772 |       | 44344   (7)| 00:00:02 |       |       |
|*  2 |   HASH JOIN                        |           |  2535K|   249M|       | 44209   (6)| 00:00:02 |       |       |
|   3 |    PART JOIN FILTER CREATE         | :BF0000   |  2556 | 30672 |       |     1   (0)| 00:00:01 |       |       |
|   4 |     TABLE ACCESS INMEMORY FULL     | DATE_DIM  |  2556 | 30672 |       |     1   (0)| 00:00:01 |       |       |
|*  5 |    HASH JOIN                       |           |  2535K|   220M|    12M| 44194   (6)| 00:00:02 |       |       |
|   6 |     TABLE ACCESS INMEMORY FULL     | PART      |   800K|  3906K|       |    77   (8)| 00:00:01 |       |       |
|*  7 |     HASH JOIN                      |           |  2535K|   207M|  2688K| 31688   (9)| 00:00:02 |       |       |
|   8 |      JOIN FILTER CREATE            | :BF0001   | 59761 |  1984K|       |    41  (25)| 00:00:01 |       |       |
|*  9 |       TABLE ACCESS INMEMORY FULL   | CUSTOMER  | 59761 |  1984K|       |    41  (25)| 00:00:01 |       |       |
|* 10 |      HASH JOIN                     |           |  8510K|   422M|       |  5668  (44)| 00:00:01 |       |       |
|  11 |       JOIN FILTER CREATE           | :BF0002   |  4102 | 73836 |       |     4  (25)| 00:00:01 |       |       |
|* 12 |        TABLE ACCESS INMEMORY FULL  | SUPPLIER  |  4102 | 73836 |       |     4  (25)| 00:00:01 |       |       |
|  13 |       JOIN FILTER USE              | :BF0001   |    41M|  1354M|       |  5434  (41)| 00:00:01 |       |       |
|  14 |        JOIN FILTER USE             | :BF0002   |    41M|  1354M|       |  5434  (41)| 00:00:01 |       |       |
|  15 |         PARTITION RANGE JOIN-FILTER|           |    41M|  1354M|       |  5434  (41)| 00:00:01 |:BF0000|:BF0000|
|* 16 |          TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|  1354M|       |  5434  (41)| 00:00:01 |:BF0000|:BF0000|
------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")5 - access("L"."LO_PARTKEY"="P"."P_PARTKEY")7 - access("L"."LO_CUSTKEY"="C"."C_CUSTKEY")9 - inmemory("C"."C_REGION"='AMERICA')filter("C"."C_REGION"='AMERICA')10 - access("L"."LO_SUPPKEY"="S"."S_SUPPKEY")12 - inmemory("S"."S_REGION"='AMERICA')filter("S"."S_REGION"='AMERICA')16 - inmemory(SYS_OP_BLOOM_FILTER_LIST(SYS_OP_BLOOM_FILTER(:BF0002,"L"."LO_SUPPKEY"),SYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_CUSTKEY")))filter(SYS_OP_BLOOM_FILTER_LIST(SYS_OP_BLOOM_FILTER(:BF0002,"L"."LO_SUPPKEY"),SYS_OP_BLOOM_FILTER(:BF0001,"L"."LO_CUSTKEY")))

在这个实验室中,我们的表非常小,但随着表的大小增加,性能差异通常会大得多。 这就是为什么我们说您通常可以期望使用内存聚合至少可以提高 3-8 倍的性能。

在没有Database In-Memory时,向量转换也是可以用的,不过慢了7倍。

SQL> @08_vgb_buffer.sql
-- 耗时
Elapsed: 00:00:04.76-- 执行计划
--------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name                      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |                           |       |       | 89852 (100)|          |       |       |
|   1 |  TEMP TABLE TRANSFORMATION               |                           |       |       |            |          |       |       |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6647_53FD65 |       |       |            |          |       |       |
|   3 |    HASH GROUP BY                         |                           |     7 |   112 |     8  (13)| 00:00:01 |       |       |
|   4 |     KEY VECTOR CREATE BUFFERED           | :KV0000                   |     7 |   112 |     7   (0)| 00:00:01 |       |       |
|   5 |      TABLE ACCESS FULL                   | DATE_DIM                  |  2556 | 30672 |     7   (0)| 00:00:01 |       |       |
|   6 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6644_53FD65 |       |       |            |          |       |       |
|   7 |    HASH GROUP BY                         |                           |     1 |     9 |  1944   (3)| 00:00:01 |       |       |
|   8 |     KEY VECTOR CREATE BUFFERED           | :KV0001                   |     1 |     9 |  1904   (1)| 00:00:01 |       |       |
|   9 |      TABLE ACCESS FULL                   | PART                      |   800K|  3906K|  1901   (1)| 00:00:01 |       |       |
|  10 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6645_53FD65 |       |       |            |          |       |       |
|  11 |    HASH GROUP BY                         |                           |     1 |    22 |    71   (3)| 00:00:01 |       |       |
|  12 |     KEY VECTOR CREATE BUFFERED           | :KV0002                   |     1 |    22 |    70   (2)| 00:00:01 |       |       |
|* 13 |      TABLE ACCESS FULL                   | SUPPLIER                  |  4102 | 73836 |    70   (2)| 00:00:01 |       |       |
|  14 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6646_53FD65 |       |       |            |          |       |       |
|  15 |    HASH GROUP BY                         |                           |    25 |   950 |   848   (2)| 00:00:01 |       |       |
|  16 |     KEY VECTOR CREATE BUFFERED           | :KV0003                   |    25 |   950 |   845   (2)| 00:00:01 |       |       |
|* 17 |      TABLE ACCESS FULL                   | CUSTOMER                  | 59761 |  1984K|   844   (2)| 00:00:01 |       |       |
|  18 |   SORT GROUP BY                          |                           |    62 |  6510 | 86982   (2)| 00:00:04 |       |       |
|* 19 |    HASH JOIN                             |                           |    62 |  6510 | 86981   (2)| 00:00:04 |       |       |
|* 20 |     HASH JOIN                            |                           |    62 |  4712 | 86979   (2)| 00:00:04 |       |       |
|  21 |      MERGE JOIN CARTESIAN                |                           |     7 |   329 |     6   (0)| 00:00:01 |       |       |
|  22 |       MERGE JOIN CARTESIAN               |                           |     1 |    31 |     4   (0)| 00:00:01 |       |       |
|  23 |        TABLE ACCESS FULL                 | SYS_TEMP_0FD9D6644_53FD65 |     1 |     9 |     2   (0)| 00:00:01 |       |       |
|  24 |        BUFFER SORT                       |                           |     1 |    22 |     2   (0)| 00:00:01 |       |       |
|  25 |         TABLE ACCESS FULL                | SYS_TEMP_0FD9D6645_53FD65 |     1 |    22 |     2   (0)| 00:00:01 |       |       |
|  26 |       BUFFER SORT                        |                           |     7 |   112 |     4   (0)| 00:00:01 |       |       |
|  27 |        TABLE ACCESS FULL                 | SYS_TEMP_0FD9D6647_53FD65 |     7 |   112 |     2   (0)| 00:00:01 |       |       |
|  28 |      VIEW                                | VW_VT_80F21617            |    62 |  1798 | 86973   (2)| 00:00:04 |       |       |
|  29 |       VECTOR GROUP BY                    |                           |    62 |  3100 | 86973   (2)| 00:00:04 |       |       |
|  30 |        HASH GROUP BY                     |                           |    62 |  3100 | 86973   (2)| 00:00:04 |       |       |
|  31 |         KEY VECTOR USE                   | :KV0000                   |  2535K|   120M| 86970   (2)| 00:00:04 |       |       |
|  32 |          KEY VECTOR USE                  | :KV0001                   |  2535K|   111M| 86970   (2)| 00:00:04 |       |       |
|  33 |           KEY VECTOR USE                 | :KV0003                   |  2535K|   101M| 86970   (2)| 00:00:04 |       |       |
|  34 |            KEY VECTOR USE                | :KV0002                   |  8510K|   308M| 86969   (2)| 00:00:04 |       |       |
|  35 |             PARTITION RANGE ITERATOR     |                           |    41M|  1354M| 86968   (2)| 00:00:04 |:KV0000|:KV0000|
|* 36 |              TABLE ACCESS FULL           | LINEORDER                 |    41M|  1354M| 86968   (2)| 00:00:04 |:KV0000|:KV0000|
|  37 |     TABLE ACCESS FULL                    | SYS_TEMP_0FD9D6646_53FD65 |    25 |   725 |     2   (0)| 00:00:01 |       |       |
--------------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------13 - filter("S"."S_REGION"='AMERICA')17 - filter("C"."C_REGION"='AMERICA')19 - access("ITEM_14"=INTERNAL_FUNCTION("C0"))20 - access("ITEM_12"=INTERNAL_FUNCTION("C0") AND "ITEM_13"=INTERNAL_FUNCTION("C0") AND "ITEM_15"=INTERNAL_FUNCTION("C0"))36 - filter((SYS_OP_KEY_VECTOR_FILTER("L"."LO_SUPPKEY",:KV0002) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_CUSTKEY",:KV0003) ANDSYS_OP_KEY_VECTOR_FILTER("L"."LO_PARTKEY",:KV0001) AND SYS_OP_KEY_VECTOR_FILTER("L"."LO_ORDERDATE",:KV0000)))Note
------ vector transformation used for this statement

在buffer cache中,如果禁用向量转换呢?慢了15倍。

SQL> @09_novgb_buffer.sql
-- 耗时
Elapsed: 00:00:10.19-- 执行计划
----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |           |       |       |       |   128K(100)|          |       |       |
|   1 |  SORT GROUP BY                   |           |   124 | 12772 |       |   128K  (2)| 00:00:06 |       |       |
|*  2 |   HASH JOIN                      |           |  2535K|   249M|       |   128K  (2)| 00:00:06 |       |       |
|   3 |    PART JOIN FILTER CREATE       | :BF0000   |  2556 | 30672 |       |     7   (0)| 00:00:01 |       |       |
|   4 |     TABLE ACCESS FULL            | DATE_DIM  |  2556 | 30672 |       |     7   (0)| 00:00:01 |       |       |
|*  5 |    HASH JOIN                     |           |  2535K|   220M|    12M|   128K  (2)| 00:00:06 |       |       |
|   6 |     TABLE ACCESS FULL            | PART      |   800K|  3906K|       |  1901   (1)| 00:00:01 |       |       |
|*  7 |     HASH JOIN                    |           |  2535K|   207M|  2688K|   114K  (2)| 00:00:05 |       |       |
|*  8 |      TABLE ACCESS FULL           | CUSTOMER  | 59761 |  1984K|       |   844   (2)| 00:00:01 |       |       |
|*  9 |      HASH JOIN                   |           |  8510K|   422M|       | 87268   (2)| 00:00:04 |       |       |
|* 10 |       TABLE ACCESS FULL          | SUPPLIER  |  4102 | 73836 |       |    70   (2)| 00:00:01 |       |       |
|  11 |       PARTITION RANGE JOIN-FILTER|           |    41M|  1354M|       | 86968   (2)| 00:00:04 |:BF0000|:BF0000|
|  12 |        TABLE ACCESS FULL         | LINEORDER |    41M|  1354M|       | 86968   (2)| 00:00:04 |:BF0000|:BF0000|
----------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("L"."LO_ORDERDATE"="D"."D_DATEKEY")5 - access("L"."LO_PARTKEY"="P"."P_PARTKEY")7 - access("L"."LO_CUSTKEY"="C"."C_CUSTKEY")8 - filter("C"."C_REGION"='AMERICA')9 - access("L"."LO_SUPPKEY"="S"."S_SUPPKEY")10 - filter("S"."S_REGION"='AMERICA')

小节:
本节主要介绍了布隆过滤器和向量转换。

实验 6:JSON 和 In-Memory 列存储

简介

Oracle 数据库在 12.1 中引入了对 JSON 数据的支持,并且在 Oracle 数据库 12c 第 2 版 (12.2) 中添加了对可以填充到 IM 列存储中的二进制 JSON 格式的支持。 这使 Oracle 数据库能够利用 DBIM 功能并允许直接对 JSON 数据进行高性能分析。 事实上,从 Oracle Database 21c 开始,现在支持 JSON 数据类型,并且也可以在 IM 列存储中填充。 请注意,要在 IM 列存储中填充的 JSON 文档必须小于 32,767 字节。 如果它大于 32,767 字节,则将在没有内存优化的情况下对其进行处理。

在本实验中,您将了解 21c 之前的 IM 列存储如何支持 JSON 数据,以及 21c 和新的 JSON 数据类型如何支持它。

任务 1:验证在 IM 列存储中填充 JSON 数据的先决条件

此实验的主要脚本执行序列如下,后面会详述:

@01_disable_tables.sql
@02_json_prereq.sql
@03_j_purchaseorder.sql
@04_enable_json.sql
@05_json_query.sql
@06_json_pop.sql
@07_im_populated.sql
@08_ime_usage.sql
@09_json_query.sql
@10_json_purchaseorder.sql
@11_json_pop.sql
@12_im_populated.sql
@13_json_query.sql
@14_json_cleanup.sql

要在 IM 列存储中填充 JSON 数据,必须设置几个数据库先决条件。 下面列出了这些先决条件,所有这些都已针对您的 LiveLabs 环境完成:

  • 数据库兼容性设置为 12.2.0 或更高版本
  • MAX_STRING_SIZE 设置为“EXTENDED”
  • INMEMORY_EXPRESSIONS_USAGE 设置为 ‘STATIC_ONLY’ 或 ‘ENABLE’
  • INMEMORY_VIRTUAL_COLUMNS 设置为“启用”

JSON 数据列在 21c 之前必须具有“IS JSON”检查约束。 在 21c 中,JSON 数据类型的列不需要检查约束,但 compatible 参数必须至少设置为 20。

实验前,需要执行以下:

. ~/.set-env-db.sh CDB1

进入json目录,登录数据库:

cd /home/oracle/labs/inmemory/json
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

由于本实验用了新的测试表,因此需要将之前的表从内存中清出:

SQL> @01_disable_tables.sql

这段PL/SQL代码值得学习,分别考虑了普通表和分区表:

set serveroutput on;
declarev_ddl varchar2(1000);
beginfor tab_cursor in (select owner, table_namefrom   dba_tableswhere  owner not in ('AUDSYS','SYS')and    inmemory = 'ENABLED')loopv_ddl := 'alter table '||tab_cursor.owner||'.'||tab_cursor.table_name||' no inmemory';dbms_output.put_line(v_ddl);execute immediate v_ddl;end loop;--for part_cursor in (select table_owner, table_name, partition_namefrom   dba_tab_partitionswhere  table_owner not in ('AUDSYS','SYS')and    inmemory = 'ENABLED')loopv_ddl := 'alter table '||part_cursor.table_owner||'.'||part_cursor.table_name||' modify partition '||part_cursor.partition_name||' no inmemory';dbms_output.put_line(v_ddl);execute immediate v_ddl;end loop;
end;
/

确认先决条件:

SQL> @02_json_prereq.sql
Connected.NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
compatible                           string      21.0.0
noncdb_compatible                    boolean     FALSENAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
max_string_size                      string      EXTENDEDNAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_expressions_usage           string      ENABLENAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_virtual_columns             string      ENABLE

任务 2:在 21c 之前填充 IM 列存储中的 JSON 数据

首先,我们将显示 J_PURCHASEORDER 表。 这是我们将用于示例的表(其实也是Oracle标准的示例表),与 19c JSON 开发人员指南中创建和使用的表相同。

SQL> @03_j_purchaseorder.sql
Connected.Name                                      Null?    Type----------------------------------------- -------- ----------------------------ID                                        NOT NULL VARCHAR2(32)DATE_LOADED                                        TIMESTAMP(6) WITH TIME ZONEPO_DOCUMENT                                        VARCHAR2(32767)TABLE_NAME           COLUMN_NAME                    DATA_TYPE                      DATA_LENGTH DATA_DEFAULT
-------------------- ------------------------------ ------------------------------ ----------- ------------------------------
J_PURCHASEORDER      ID                             VARCHAR2                                32
J_PURCHASEORDER      DATE_LOADED                    TIMESTAMP(6) WITH TIME ZONE             13
J_PURCHASEORDER      PO_DOCUMENT                    VARCHAR2                             32767TABLE_NAME           CONSTRAINT_NAME      C SEARCH_CONDITION
-------------------- -------------------- - ------------------------------
J_PURCHASEORDER      SYS_C008287          C "ID" IS NOT NULL
J_PURCHASEORDER      SYS_C008289          P

PO_DOCUMENT列存放的是JSON数据,目前列上还没有关于JSON的约束。

下一步将在 PO_DOCUMENT 列上定义检查约束,以确保 JSON 格式正确并启用 JSON 数据的内存优化。因为有数据(640000行),alter table会慢一点。

SQL> @04_enable_json.sql
Connected.
SQL>
SQL> alter table j_purchaseorder add constraint ensure_json check (po_document is json);Table altered.SQL>
SQL> set echo offTABLE_NAME           COLUMN_NAME                    DATA_TYPE                      DATA_LENGTH DATA_DEFAULT
-------------------- ------------------------------ ------------------------------ ----------- ------------------------------
J_PURCHASEORDER      ID                             VARCHAR2                                32
J_PURCHASEORDER      DATE_LOADED                    TIMESTAMP(6) WITH TIME ZONE             13
J_PURCHASEORDER      PO_DOCUMENT                    VARCHAR2                             32767
J_PURCHASEORDER      SYS_IME_OSON_00242D59FB994F94B RAW                                  32767 OSON("PO_DOCUMENT" FORMAT JSONF9AEE8C6586313E                                                            , 'ime' RETURNING RAW(32767)NULL ON ERROR)TABLE_NAME           CONSTRAINT_NAME      C SEARCH_CONDITION
-------------------- -------------------- - ------------------------------
J_PURCHASEORDER      SYS_C008287          C "ID" IS NOT NULL
J_PURCHASEORDER      ENSURE_JSON          C po_document is json
J_PURCHASEORDER      SYS_C008289          P

请注意,我们不仅在 PO_DOCUMENT 列上创建了检查约束,而且还导致创建了一个以名称 SYS_IME_OSON 开头的新虚拟列。 Oracle 数据库创建了 PO_DOCUMENT 列的特殊二进制版本(这意味着需要额外的存储空间)。

开始JSON查询,此时表还没有发布:

SQL> @05_json_query.sql
-- 耗时
Elapsed: 00:00:12.78-- 执行计划
----------------------------------------------------------------------------------------------------
| Id  | Operation                | Name            | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                 |       |       |       |  2968M(100)|          |
|   1 |  SORT ORDER BY           |                 | 10000 |    18M|  9970G|  2968M  (1)| 32:12:43 |
|   2 |   HASH GROUP BY          |                 | 10000 |    18M|  9970G|  2968M  (1)| 32:12:43 |
|   3 |    NESTED LOOPS          |                 |  5227M|  9357G|       |    17M  (1)| 00:11:22 |
|*  4 |     TABLE ACCESS FULL    | J_PURCHASEORDER |   640K|  1170M|       | 26402   (1)| 00:00:02 |
|   5 |     JSONTABLE EVALUATION |                 |       |       |       |            |          |
----------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------4 - filter(INTERNAL_FUNCTION("PO_DOCUMENT" /*+ LOB_BY_VALUE */ ))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                           1288
physical reads                                                    96829
session logical reads                                            100861
session pga memory                                             19401008

发布表:

SQL> @@06_json_pop.sql
Connected.
SQL>
SQL> alter table j_purchaseorder inmemory;Table altered.SQL>
SQL> exec dbms_inmemory.populate(USER, 'J_PURCHASEORDER');PL/SQL procedure successfully completed.SQL>
SQL> set echo off

确认发布:

SQL> @@07_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        J_PURCHASEORDER                      COMPLETED            793,198,592    1,056,702,464                0SQL>
SQL> set echo off

注意到消耗的内存比磁盘空间大。

由于创建了虚拟列,它将作为内存中表达式 (IME) 存储在 IM 列存储中。 让我们检查一下二进制 JSON 数据需要多少额外空间。

SQL> @08_ime_usage.sql
Connected.
SQL>
SQL> -- This query displays what objects are in the In-Memory Column Store
SQL>
SQL> select2    o.owner,3    o.object_name,4    o.subobject_name as partition_name,5    i.column_name,6    count(*) t_imeu,7    sum(i.length)/1024/1024 space8  from9    v$im_imecol_cu i,10    dba_objects o11  where12    i.objd = o.object_id13  group by14    o.owner,15    o.object_name,16    o.subobject_name,17    i.column_name;Partition            Column            Total         Used
Owner      Object               Name                 Name              IMEUs    Space(MB)
---------- -------------------- -------------------- --------------- ------- ------------
SSB        J_PURCHASEORDER                           SYS_IME_OSON_00      11           83242D59FB994F94BF9AEE8C6586313ESQL>
SQL> set echo off

空间不大,但它确实需要 IM 列存储中的一些额外空间,以便存储内存中优化的 JSON 数据。

再次运行查询,快了2.6倍:

SQL> @09_json_query.sql
-- 耗时
Elapsed: 00:00:04.88-- 执行计划
---------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                 |       |       |       |  2968M(100)|          |
|   1 |  SORT ORDER BY                |                 | 10000 |    18M|  9970G|  2968M  (1)| 32:12:42 |
|   2 |   HASH GROUP BY               |                 | 10000 |    18M|  9970G|  2968M  (1)| 32:12:42 |
|   3 |    NESTED LOOPS               |                 |  5227M|  9357G|       |    17M  (1)| 00:11:21 |
|*  4 |     TABLE ACCESS INMEMORY FULL| J_PURCHASEORDER |   640K|  1170M|       |   986   (1)| 00:00:01 |
|   5 |     JSONTABLE EVALUATION      |                 |       |       |       |            |          |
---------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------4 - filter(INTERNAL_FUNCTION("PO_DOCUMENT" /*+ LOB_BY_VALUE */ ))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            491
IM scan CUs columns accessed                                         11
IM scan CUs memcompress for query low                                11
IM scan EU rows                                                  640000
IM scan EUs columns accessed                                         11
IM scan EUs memcompress for query low                                11
IM scan rows                                                     640000
IM scan rows pcode aggregated                                    640000
IM scan rows projected                                           639999
IM scan rows valid                                               640000
session logical reads                                             96919
session logical reads - IM                                        96826
session pga memory                                             18024752
table scans (IM)                                                      114 rows selected.

这里有几点需要注意。 首先是查询运行了大约一半的时间。 这是一个相当不错的加速。 二是看统计数据。 请注意,现在有“IM scan EU”统计信息。 这是因为二进制 JSON 数据利用了另一个名为 In-Memory Expressions 的 Database In-Memory 功能。

任务 3:使用 21c 中的 JSON 数据类型填充 IM 列中的 JSON 数据

现在让我们切换到一个将 PO_DOCUMENT 列定义为 JSON 数据类型的新表JSON_PURCHASEORDER(之前的表为J_PURCHASEORDER,两个表都是640000行)。 JSON数据类型是 Oracle Database 21c 中的新功能。

SQL> @10_json_purchaseorder.sql
Connected.Column
TABLE_NAME           Name                           DATA_TYPE                      DATA_LENGTH DATA_DEFAULT
-------------------- ------------------------------ ------------------------------ ----------- ------------------------------
JSON_PURCHASEORDER   ID                             VARCHAR2                                32
JSON_PURCHASEORDER   DATE_LOADED                    TIMESTAMP(6) WITH TIME ZONE             13
JSON_PURCHASEORDER   PO_DOCUMENT                    JSON                                  8200
JSON_PURCHASEORDER   SYS_IME_OSON_9BCF95B616674FF9B RAW                                  32767 OSON("PO_DOCUMENT" FORMAT OSONFE78D6675051BFE                                                            , 'ime' RETURNING RAW(32767)NULL ON ERROR)TABLE_NAME           CONSTRAINT_NAME      C SEARCH_CONDITION
-------------------- -------------------- - ------------------------------
JSON_PURCHASEORDER   SYS_C008286          C "ID" IS NOT NULL
JSON_PURCHASEORDER   SYS_C008288          P

对于JSON数据类型,我们无需再建立约束。

发布:

SQL> @11_json_pop.sql
Connected.
SQL>
SQL> alter table j_purchaseorder no inmemory;Table altered.SQL>
SQL> alter table json_purchaseorder inmemory;Table altered.SQL>
SQL> exec dbms_inmemory.populate(USER, 'JSON_PURCHASEORDER');PL/SQL procedure successfully completed.SQL>
SQL> set echo off

确认已发布:

SQL> @12_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by inmemory_size;Partition                                               In-Memory            Bytes
Owner      SEGMENT_NAME         Name            POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        JSON_PURCHASEORDER                   COMPLETED            691,912,704      790,298,624                0SQL>
SQL> set echo off

虽然内存占用仍比磁盘多,但内存空间和磁盘空间相比21c之前的JSON列,已经小一些了。

内存中的查询:

SQL> @13_json_query.sql
-- 耗时
Elapsed: 00:00:04.94 -- 执行计划
----------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                    |       |       |    18M(100)|          |
|   1 |  SORT ORDER BY                |                    |     1 |   851 |    18M  (6)| 00:11:53 |
|   2 |   HASH GROUP BY               |                    |     1 |   851 |    18M  (6)| 00:11:53 |
|   3 |    NESTED LOOPS               |                    |  5227M|  4143G|    17M  (1)| 00:11:21 |
|   4 |     TABLE ACCESS INMEMORY FULL| JSON_PURCHASEORDER |   640K|   516M|   862   (1)| 00:00:01 |
|   5 |     JSONTABLE EVALUATION      |                    |       |       |            |          |
------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            495
IM scan CUs columns accessed                                         10
IM scan CUs memcompress for query low                                10
IM scan rows                                                     640000
IM scan rows projected                                           639999
IM scan rows valid                                               640000
physical reads                                                        4
session logical reads                                             84570
session logical reads - IM                                        84462
session pga memory                                             18024752
table scans (IM)                                                      111 rows selected.

性能和21c前的JSON列基本相同,慢了一点点(原文也是如此)。但空间效率胜出。

清理:

SQL> @14_json_cleanup.sql
Connected.
SQL>
SQL> alter table json_purchaseorder no inmemory;Table altered.SQL>
SQL> alter table j_purchaseorder drop constraint ensure_json;Table altered.SQL>
SQL> set echo off

实验 7: Automatic In-Memory 级别HIGH

背景知识

在 Oracle Database 18c 中添加了一个名为 Automatic In-Memory (AIM) 的特性。 AIM 的目标是根据使用情况管理 IM 列存储的内容。 AIM 最初有两个级别,LOW 和 MEDIUM,一旦 IM 列存储已满,就可以自动管理 IM 列存储内容。 在 Oracle Database 21c 中添加了第三个级别HIGH,它可以自动管理所有非系统段,而无需先启用内存中的对象。

本实验室将探索新的 AIM 级别 HIGH 及其工作原理。 将使用一个新模式,即具有小型、中型和大型表的 AIM 模式。 这将更容易展示 AIM 在列存储遇到“内存压力”(即已满)时如何工作。 SSB 模式中的 LINEORDER 表将用于帮助“填充”IM 列存储,然后 AIM 表将用于显示 AIM 如何管理对象总数以获得最大收益。

这几个大表位于aim schema,可以通过以下脚本创建,你无需执行。

create table lrgtab1 as select/*+ append */  * from ssb.lineorder where rownum <= 5000000;
create table lrgtab2 as select/*+ append */  * from ssb.lineorder where rownum <= 5000000;
create table lrgtab3 as select/*+ append */  * from ssb.lineorder where rownum <= 5000000;
create table lrgtab4 as select/*+ append */  * from ssb.lineorder where rownum <= 5000000;create table medtab1 as select /*+ append */  * from ssb.customer where rownum <= 300000;
create table medtab2 as select /*+ append */  * from ssb.customer where rownum <= 300000;
create table medtab3 as select /*+ append */  * from ssb.customer where rownum <= 300000;
create table medtab4 as select /*+ append */  * from ssb.customer where rownum <= 300000;create table smtab1 as select /*+ append */  * from ssb.supplier where rownum <= 20000;
create table smtab2 as select /*+ append */  * from ssb.supplier where rownum <= 20000;
create table smtab3 as select /*+ append */  * from ssb.supplier where rownum <= 20000;
create table smtab4 as select /*+ append */  * from ssb.supplier where rownum <= 20000;

此实验的主要脚本执行序列如下,后面会详述:

@02_disable_tables.sql
@03_pop_ssb_tables.sql
@04_im_populated.sql
@05_aim_attributes.sql
@06_aim_high.sql
@07_aim_attributes.sql
@08_im_populated.sql
@09_pop_aim_tables.sql
@10_im_populated.sql
@11_hm_stats.sql
@12_aimtasks.sql
@13_aimtaskdetails.sql
@14_aim_off.sql
@15_aim_attributes.sql
@16_im_populated.sql
@17_aim-high_cleanup.sql

实验前,需要执行以下:

. ~/.set-env-db.sh CDB1

进入aim-high目录,登录数据库:

cd /home/oracle/labs/inmemory/aim-high
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

首先让我们检查 SSB 和 AIM 模式中对象的内存状态:

SQL> @01_aim_attributes.sql
Connected.
SQL>
SQL> -- Show table attributes
SQL>
SQL> select owner, table_name, NULL as partition_name, inmemory,2         inmemory_priority, inmemory_distribute, inmemory_compression3  from   dba_tables4  where owner in ('AIM','SSB')5  UNION ALL6  select table_owner as owner, table_name, partition_name, inmemory,7         inmemory_priority, inmemory_distribute, inmemory_compression8  from   dba_tab_partitions9  where table_owner in ('AIM','SSB')10  order by owner, table_name, partition_name;INMEMORY   INMEMORY     INMEMORY
OWNER      TABLE_NAME           PARTITION_NAME  INMEMORY   PRIORITY   DISTRIBUTE   COMPRESSION
---------- -------------------- --------------- ---------- ---------- ------------ --------------
AIM        LRGTAB1                              DISABLED
AIM        LRGTAB2                              DISABLED
AIM        LRGTAB3                              DISABLED
AIM        LRGTAB4                              DISABLED
AIM        MEDTAB1                              DISABLED
AIM        MEDTAB2                              DISABLED
AIM        MEDTAB3                              DISABLED
AIM        SMTAB1                               DISABLED
AIM        SMTAB2                               DISABLED
AIM        SMTAB3                               DISABLED
SSB        CHICAGO_DATA                         DISABLED
SSB        CUSTOMER                             DISABLED
SSB        DATE_DIM                             DISABLED
SSB        EXT_CUST_BULGARIA                    DISABLED
SSB        EXT_CUST_NORWAY                      DISABLED
SSB        JSON_PURCHASEORDER                   DISABLED
SSB        J_PURCHASEORDER                      DISABLED
SSB        LINEORDER            PART_1994       DISABLED
SSB        LINEORDER            PART_1995       DISABLED
SSB        LINEORDER            PART_1996       DISABLED
SSB        LINEORDER            PART_1997       DISABLED
SSB        LINEORDER            PART_1998       DISABLED
SSB        LINEORDER
SSB        PART                                 DISABLED
SSB        SUPPLIER                             DISABLED25 rows selected.SQL>
SQL> set echo off

接下来,我们将验证所有的表都为 INMEMORY 禁用,以便我们可以确保我们将从干净的设置开始。

SQL> @02_disable_tables.sql
Connected.
alter table AIM.MEDTAB2 no inmemory
alter table AIM.SMTAB3 no inmemory
alter table AIM.LRGTAB3 no inmemory
alter table AIM.LRGTAB2 no inmemory
alter table AIM.LRGTAB1 no inmemory
alter table AIM.SMTAB1 no inmemory
alter table AIM.MEDTAB1 no inmemory
alter table AIM.MEDTAB3 no inmemory
alter table AIM.LRGTAB4 no inmemory
alter table AIM.SMTAB2 no inmemory
alter table SSB.SUPPLIER no inmemory
alter table SSB.DATE_DIM no inmemory
alter table SSB.PART no inmemory
alter table SSB.EXT_CUST_BULGARIA no inmemory
alter table SSB.EXT_CUST_NORWAY no inmemory
alter table SSB.CUSTOMER no inmemory
alter table SSB.CHICAGO_DATA no inmemory
alter table SSB.JSON_PURCHASEORDER no inmemory
alter table SSB.J_PURCHASEORDER no inmemory
alter table SSB.LINEORDER no inmemory
alter table SSB.LINEORDER modify partition PART_1994 no inmemory
alter table SSB.LINEORDER modify partition PART_1995 no inmemory
alter table SSB.LINEORDER modify partition PART_1996 no inmemory
alter table SSB.LINEORDER modify partition PART_1997 no inmemory
alter table SSB.LINEORDER modify partition PART_1998 no inmemoryPL/SQL procedure successfully completed.

现在我们将填充 LINEORDER 分区。 由于我们明确启用了 INMEMORY 分区,因此 AIM 不会触及它们。 这些分区将充当常量填充器,以便 IM 列存储接近满。 这将更容易确保 IM 列存储处于内存压力之下。 回想一下,这是 AIM 运行所必需的。

SQL> @03_pop_ssb_tables.sql
Connected.
SQL>
SQL> alter table ssb.lineorder inmemory priority high;Table altered.SQL>
SQL> exec dbms_inmemory.populate('SSB','LINEORDER');PL/SQL procedure successfully completed.SQL>
SQL> set echo off

验证是否填充了所有 LINEORDER 分区。

SQL> @04_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  where owner not in ('AUDSYS','SYS')5  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0SQL>
SQL> select * from v$inmemory_area;POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
-------------------------- ----------- ---------- --------------- ----------
1MB POOL                    3252682752 2191523840 DONE                     3
64KB POOL                    201326592    5439488 DONE                     3SQL>
SQL> set echo off

确认所有 LINEORDER 分区都已填充,然后再继续实验室。 您可能需要重新运行此脚本来验证分区是否已填充,因为完全填充分区确实需要一些时间。

让我们重新检查 SSB 和 AIM 模式中对象的内存状态:

SQL> @05_aim_attributes.sql
Connected.
SQL>
SQL> -- Show table attributes
SQL>
SQL> select owner, table_name, NULL as partition_name, inmemory,2         inmemory_priority, inmemory_distribute, inmemory_compression3  from   dba_tables4  where owner in ('AIM','SSB')5  UNION ALL6  select table_owner as owner, table_name, partition_name, inmemory,7         inmemory_priority, inmemory_distribute, inmemory_compression8  from   dba_tab_partitions9  where table_owner in ('AIM','SSB')10  order by owner, table_name, partition_name;INMEMORY   INMEMORY     INMEMORY
OWNER      TABLE_NAME           PARTITION_NAME  INMEMORY   PRIORITY   DISTRIBUTE   COMPRESSION
---------- -------------------- --------------- ---------- ---------- ------------ --------------
AIM        LRGTAB1                              DISABLED
AIM        LRGTAB2                              DISABLED
AIM        LRGTAB3                              DISABLED
AIM        LRGTAB4                              DISABLED
AIM        MEDTAB1                              DISABLED
AIM        MEDTAB2                              DISABLED
AIM        MEDTAB3                              DISABLED
AIM        SMTAB1                               DISABLED
AIM        SMTAB2                               DISABLED
AIM        SMTAB3                               DISABLED
SSB        CHICAGO_DATA                         DISABLED
SSB        CUSTOMER                             DISABLED
SSB        DATE_DIM                             DISABLED
SSB        EXT_CUST_BULGARIA                    DISABLED
SSB        EXT_CUST_NORWAY                      DISABLED
SSB        JSON_PURCHASEORDER                   DISABLED
SSB        J_PURCHASEORDER                      DISABLED
SSB        LINEORDER            PART_1994       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1995       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1996       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1997       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1998       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER
SSB        PART                                 DISABLED
SSB        SUPPLIER                             DISABLED25 rows selected.

请注意,LINEORDER 分区现在已启用内存,但所有其他对象的内存状态为空白或禁用。

现在我们将启用 AIM HIGH级别。

SQL> @06_aim_high.sql
Connected.NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_automatic_level             string      OFFSystem altered.NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_automatic_level             string      HIGH

让我们重新检查 SSB 和 AIM 模式中对象的内存状态:

SQL> @07_aim_attributes.sql
Connected.
SQL>
SQL> -- Show table attributes
SQL>
SQL> select owner, table_name, NULL as partition_name, inmemory,2         inmemory_priority, inmemory_distribute, inmemory_compression3  from   dba_tables4  where owner in ('AIM','SSB')5  UNION ALL6  select table_owner as owner, table_name, partition_name, inmemory,7         inmemory_priority, inmemory_distribute, inmemory_compression8  from   dba_tab_partitions9  where table_owner in ('AIM','SSB')10  order by owner, table_name, partition_name;INMEMORY   INMEMORY     INMEMORY
OWNER      TABLE_NAME           PARTITION_NAME  INMEMORY   PRIORITY   DISTRIBUTE   COMPRESSION
---------- -------------------- --------------- ---------- ---------- ------------ --------------
AIM        LRGTAB1                              ENABLED    NONE       AUTO         AUTO
AIM        LRGTAB2                              ENABLED    NONE       AUTO         AUTO
AIM        LRGTAB3                              ENABLED    NONE       AUTO         AUTO
AIM        LRGTAB4                              ENABLED    NONE       AUTO         AUTO
AIM        MEDTAB1                              ENABLED    NONE       AUTO         AUTO
AIM        MEDTAB2                              ENABLED    NONE       AUTO         AUTO
AIM        MEDTAB3                              ENABLED    NONE       AUTO         AUTO
AIM        SMTAB1                               ENABLED    NONE       AUTO         AUTO
AIM        SMTAB2                               ENABLED    NONE       AUTO         AUTO
AIM        SMTAB3                               ENABLED    NONE       AUTO         AUTO
SSB        CHICAGO_DATA                         ENABLED    NONE       AUTO         AUTO
SSB        CUSTOMER                             ENABLED    NONE       AUTO         AUTO
SSB        DATE_DIM                             ENABLED    NONE       AUTO         AUTO
SSB        EXT_CUST_BULGARIA                    ENABLED    NONE       AUTO         AUTO
SSB        EXT_CUST_NORWAY                      ENABLED    NONE       AUTO         AUTO
SSB        JSON_PURCHASEORDER                   ENABLED    NONE       AUTO         AUTO
SSB        J_PURCHASEORDER                      ENABLED    NONE       AUTO         AUTO
SSB        LINEORDER            PART_1994       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1995       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1996       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1997       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1998       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER
SSB        PART                                 ENABLED    NONE       AUTO         AUTO
SSB        SUPPLIER                             ENABLED    NONE       AUTO         AUTO25 rows selected.SQL>
SQL> set echo off

请注意,现在所有表都在内存中启用,并注意除了 LINEORDER 分区之外的所有表都具有 AUTO 的内存压缩级别。 这是 AIM HIGH级别的新功能。

现在让我们看看 IM 列存储填充发生了什么。

SQL> @08_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  where owner not in ('AUDSYS','SYS')5  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0SQL>
SQL> select * from v$inmemory_area;POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
-------------------------- ----------- ---------- --------------- ----------
1MB POOL                    3252682752 2191523840 DONE                     3
64KB POOL                    201326592    5439488 DONE                     3SQL>
SQL> set echo off

没有什么不同。 请记住,AIM 仅在列存储处于内存压力下时运行,即使我们将 INMEMORY_AUTOMATIC_LEVEL 设置为高,对象仍然具有 NONE 优先级,这意味着必须先访问它们才能填充它们。 下一步将解决这个问题。

现在我们将访问四个 LRGTAB 表以开始填充这些表。

SQL> @09_pop_aim_tables.sql
Connected.
SQL>
SQL> select count(*) from lrgtab1;COUNT(*)
----------5000000SQL> select count(*) from lrgtab1;COUNT(*)
----------5000000SQL>
SQL> select count(*) from lrgtab2;COUNT(*)
----------5000000SQL> select count(*) from lrgtab2;COUNT(*)
----------5000000SQL> select count(*) from lrgtab2;COUNT(*)
----------5000000SQL>
SQL> select count(*) from lrgtab3;COUNT(*)
----------5000000SQL> select count(*) from medtab1;COUNT(*)
----------300000SQL> select count(*) from medtab1;COUNT(*)
----------300000SQL> select count(*) from medtab1;COUNT(*)
----------300000SQL> select count(*) from medtab2;COUNT(*)
----------300000SQL> select count(*) from medtab2;COUNT(*)
----------300000SQL> select count(*) from medtab2;COUNT(*)
----------300000SQL>
SQL> select count(*) from lrgtab4;COUNT(*)
----------5000000SQL> select count(*) from lrgtab4;COUNT(*)
----------5000000SQL>
SQL> set echo off

在此步骤中,我们将查看填充的段。 您可能需要多次运行此步骤以观察发布的进展情况。

SQL> @10_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  where owner not in ('AUDSYS','SYS')5  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        JSON_PURCHASEORDER                   OUT OF MEMORY        691,912,704       19,005,440      674,930,688
SSB        J_PURCHASEORDER                      COMPLETED            793,198,592      946,077,696                0
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                011 rows selected.SQL>
SQL> select * from v$inmemory_area;POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
-------------------------- ----------- ---------- --------------- ----------
1MB POOL                    3252682752 3198156800 DONE                     3
64KB POOL                    201326592    7471104 DONE                     3

此时,已经出现OUT OF MEMORY 现象。

让我们看一下各个细分市场的热图统计信息。 尽管 AIM 不直接使用热图,也不必启用 它AIM 才能工作,但它确实为我们提供了一种查看 AIM 决策所依据的使用统计数据的简单方法。

SQL> @11_hm_stats.sql
Connected.SEG        SEG        FULL       LOOKUP      NUM FULL NUM LOOKUP   NUM SEG
OWNER      OBJECT_NAME          SUBOBJECT_NAME  TRACK_TIME       WRITE      READ       SCAN       SCAN            SCAN       SCAN     WRITE
---------- -------------------- --------------- ---------------- ---------- ---------- ---------- ---------- --------- ---------- ---------
SYS        I_LTXID_TRANS$PK     LTXID_TRANS_PK_ 11/09/2022 00:58 NO         NO         NO         YES                0          1         001SYS        LTXID_TRANS          LTXID_TRANS_1   11/09/2022 00:58 NO         NO         NO         YES                0          1         0
SSB        CUSTOMER                             11/09/2022 02:20 NO         NO         YES        NO                 5          0         0
SSB        DATE_DIM                             11/09/2022 02:20 NO         NO         YES        NO                10          0         0
SSB        LINEORDER            PART_1994       11/09/2022 02:20 NO         NO         YES        YES               16          1         0
SSB        LINEORDER            PART_1995       11/09/2022 02:20 NO         NO         YES        YES               16          1         0
SSB        LINEORDER            PART_1996       11/09/2022 02:20 NO         NO         YES        YES               18      24541         0
SSB        LINEORDER            PART_1997       11/09/2022 02:20 NO         NO         YES        YES               18          1         0
SSB        LINEORDER            PART_1998       11/09/2022 02:20 NO         NO         YES        YES               16          1         0
SSB        LINEORDER_I2         PART_1994       11/09/2022 02:20 NO         NO         NO         YES                0          1         0
SSB        LINEORDER_I2         PART_1995       11/09/2022 02:20 NO         NO         NO         YES                0          1         0
SSB        LINEORDER_I2         PART_1996       11/09/2022 02:20 NO         NO         NO         YES                0          1         0
SSB        LINEORDER_I2         PART_1997       11/09/2022 02:20 NO         NO         NO         YES                0          1         0
SSB        LINEORDER_I2         PART_1998       11/09/2022 02:20 NO         NO         NO         YES                0          1         0
SSB        PART                                 11/09/2022 02:20 NO         NO         YES        NO                 7          0         0
SSB        SUPPLIER                             11/09/2022 02:20 NO         NO         YES        NO                 7          0         0
SSB        LINEORDER_I1         PART_1996       11/09/2022 03:20 NO         NO         NO         YES                0          1         0
SSB        JSON_PURCHASEORDER                   11/09/2022 04:20 NO         NO         YES        NO                 2          0         0
SSB        J_PURCHASEORDER                      11/09/2022 04:20 NO         NO         YES        NO                 4          0         0
AIM        LRGTAB1                              11/09/2022 04:36 NO         YES        YES        NO                 2          0         0
AIM        LRGTAB2                              11/09/2022 04:36 NO         YES        YES        NO                 3          0         0
AIM        LRGTAB3                              11/09/2022 04:36 NO         YES        YES        NO                 1          0         0
AIM        LRGTAB4                              11/09/2022 04:36 NO         YES        YES        NO                 2          0         0
AIM        MEDTAB1                              11/09/2022 04:36 NO         YES        YES        NO                 3          0         0
AIM        MEDTAB2                              11/09/2022 04:36 NO         YES        YES        NO                 3          0         025 rows selected.

显示的值将基于数据库中的使用情况。

现在让我们看看我们是否可以弄清楚 AIM 处理发生了什么。 首先,我们将查看作为 AIM 的一部分运行的任务。

SQL> @12_aimtasks.sql
Connected.TASK_ID CREATE_TIME                 STATE
---------- --------------------------- -------1 09-NOV-22 04:34:00          DONE2 09-NOV-22 04:34:13          DONE3 09-NOV-22 04:34:13          DONE4 09-NOV-22 04:34:14          DONE5 09-NOV-22 04:34:14          DONE6 09-NOV-22 04:34:14          DONE7 09-NOV-22 04:34:14          DONE8 09-NOV-22 04:34:14          DONE9 09-NOV-22 04:34:29          DONE10 09-NOV-22 04:34:30          DONE11 09-NOV-22 04:34:30          DONE12 09-NOV-22 04:34:31          DONE13 09-NOV-22 04:34:31          DONE14 09-NOV-22 04:34:31          DONE15 09-NOV-22 04:36:29          DONE16 09-NOV-22 04:36:33          DONE17 09-NOV-22 04:36:33          DONE17 rows selected.

记下最后一个 task_id。 我们将在下一步中使用它作为输入。 另请注意,这些任务大约每 2 分钟运行一次。 AIM 任务将在每个 IMCO 周期(大约每 2 分钟)安排一次,此时 IM 列存储处于内存压力之下。 这意味着在 IM 列存储中的 AIM 填充对象之前可能需要几个周期。

现在让我们看看 AIM 任务的详细信息,或者实际发生的情况。

SQL> @13_aimtaskdetails.sql
Connected.
Enter value for 1: 22
old   1: select * from dba_inmemory_aimtaskdetails where task_id = &1
new   1: select * from dba_inmemory_aimtaskdetails where task_id = 22TASK_ID OBJECT_OWNER    OBJECT_NAME                    SUBOBJECT_NAME                 ACTION           STATE
---------- --------------- ------------------------------ ------------------------------ ---------------- ----------22 AIM             LRGTAB1                                                       NO ACTION        DONE22 AIM             LRGTAB2                                                       NO ACTION        DONE22 AIM             LRGTAB3                                                       NO ACTION        DONE22 AIM             LRGTAB4                                                       NO ACTION        DONE22 AIM             MEDTAB1                                                       POPULATE         DONE22 AIM             MEDTAB2                                                       POPULATE         DONE22 AIM             MEDTAB3                                                       NO ACTION        DONE22 AIM             SMTAB1                                                        NO ACTION        DONE22 AIM             SMTAB2                                                        NO ACTION        DONE22 AIM             SMTAB3                                                        NO ACTION        DONE22 SSB             CHICAGO_DATA                                                  NO ACTION        DONE22 SSB             CUSTOMER                                                      POPULATE         DONE22 SSB             DATE_DIM                                                      POPULATE         DONE22 SSB             EXT_CUST_BULGARIA                                             NO ACTION        DONE22 SSB             EXT_CUST_NORWAY                                               NO ACTION        DONE22 SSB             JSON_PURCHASEORDER                                            NO ACTION        DONE22 SSB             J_PURCHASEORDER                                               POPULATE         DONE22 SSB             LINEORDER                      PART_1994                      POPULATE         DONE22 SSB             LINEORDER                      PART_1995                      POPULATE         DONE22 SSB             LINEORDER                      PART_1996                      POPULATE         DONE22 SSB             LINEORDER                      PART_1997                      POPULATE         DONE22 SSB             LINEORDER                      PART_1998                      POPULATE         DONE22 SSB             PART                                                          POPULATE         DONE22 SSB             SUPPLIER                                                      POPULATE         DONE24 rows selected.

查看 OBJECT_NAME 和 ACTION。 现在 IM 列存储处于内存压力之下,AIM 已经接管了对发布的控制,而且还有很多事情要做。 根据使用情况统计,AIM 将填充对正在运行的查询产生最大益处的对象。 您可能想查看其他一些任务详细信息,以更好地了解所发生的情况。 还要注意,现在 AIM 正在控制发布,优先级将被忽略,AIM 将决定填充哪些对象以及驱逐哪些对象。

前面,我们看到JSON_PURCHASEORDER处于OUT OF MEMORY状态,对其多执行几次全表扫描,会将其它对象驱逐,为其留出内存:

select /*+ full(l) noparallel(l) */ count(*) from JSON_PURCHASEORDER l;

我们可以看到其成功发布了:

SQL> @10_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  where owner not in ('AUDSYS','SYS')5  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        JSON_PURCHASEORDER                   COMPLETED            691,912,704      841,940,992                0
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                010 rows selected.SQL>
SQL> select * from v$inmemory_area;POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
-------------------------- ----------- ---------- --------------- ----------
1MB POOL                    3252682752 3075473408 DONE                     3
64KB POOL                    201326592    7012352 DONE                     3

实际上,对象J_PURCHASEORDER被清除出去(EVICT)了。

SQL> @13_aimtaskdetails.sql
Connected.
Enter value for 1: 44
old   1: select * from dba_inmemory_aimtaskdetails where task_id = &1
new   1: select * from dba_inmemory_aimtaskdetails where task_id = 44TASK_ID OBJECT_OWNER    OBJECT_NAME                    SUBOBJECT_NAME                 ACTION           STATE
---------- --------------- ------------------------------ ------------------------------ ---------------- ----------44 AIM             LRGTAB1                                                       EVICT            DONE44 AIM             LRGTAB2                                                       EVICT            DONE44 AIM             LRGTAB3                                                       EVICT            DONE44 AIM             LRGTAB4                                                       EVICT            DONE44 AIM             MEDTAB1                                                       EVICT            DONE44 AIM             MEDTAB2                                                       EVICT            DONE44 AIM             MEDTAB3                                                       EVICT            DONE44 AIM             SMTAB1                                                        EVICT            DONE44 AIM             SMTAB2                                                        EVICT            DONE44 AIM             SMTAB3                                                        EVICT            DONE44 SSB             CHICAGO_DATA                                                  EVICT            DONE44 SSB             CUSTOMER                                                      NO ACTION        DONE44 SSB             DATE_DIM                                                      POPULATE         DONE44 SSB             EXT_CUST_BULGARIA                                             EVICT            DONE44 SSB             EXT_CUST_NORWAY                                               EVICT            DONE44 SSB             JSON_PURCHASEORDER                                            PARTIAL POPULATE DONE44 SSB             J_PURCHASEORDER                                               EVICT            DONE44 SSB             LINEORDER                      PART_1994                      POPULATE         DONE44 SSB             LINEORDER                      PART_1995                      POPULATE         DONE44 SSB             LINEORDER                      PART_1996                      POPULATE         DONE44 SSB             LINEORDER                      PART_1997                      POPULATE         DONE44 SSB             LINEORDER                      PART_1998                      POPULATE         DONE44 SSB             PART                                                          NO ACTION        DONE44 SSB             SUPPLIER                                                      NO ACTION        DONE24 rows selected.

关闭AIM:

SQL> @14_aim_off.sql
Connected.NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_automatic_level             string      HIGHSystem altered.NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_automatic_level             string      OFF

让我们看看 inmemory 属性发生了什么变化。

SQL> @15_aim_attributes.sql
Connected.
SQL>
SQL> -- Show table attributes
SQL>
SQL> select owner, table_name, NULL as partition_name, inmemory,2         inmemory_priority, inmemory_distribute, inmemory_compression3  from   dba_tables4  where owner in ('AIM','SSB')5  UNION ALL6  select table_owner as owner, table_name, partition_name, inmemory,7         inmemory_priority, inmemory_distribute, inmemory_compression8  from   dba_tab_partitions9  where table_owner in ('AIM','SSB')10  order by owner, table_name, partition_name;INMEMORY   INMEMORY     INMEMORY
OWNER      TABLE_NAME           PARTITION_NAME  INMEMORY   PRIORITY   DISTRIBUTE   COMPRESSION
---------- -------------------- --------------- ---------- ---------- ------------ --------------
AIM        LRGTAB1                              DISABLED
AIM        LRGTAB2                              DISABLED
AIM        LRGTAB3                              DISABLED
AIM        LRGTAB4                              DISABLED
AIM        MEDTAB1                              DISABLED
AIM        MEDTAB2                              DISABLED
AIM        MEDTAB3                              DISABLED
AIM        SMTAB1                               DISABLED
AIM        SMTAB2                               DISABLED
AIM        SMTAB3                               DISABLED
SSB        CHICAGO_DATA                         DISABLED
SSB        CUSTOMER                             DISABLED
SSB        DATE_DIM                             DISABLED
SSB        EXT_CUST_BULGARIA                    DISABLED
SSB        EXT_CUST_NORWAY                      DISABLED
SSB        JSON_PURCHASEORDER                   DISABLED
SSB        J_PURCHASEORDER                      DISABLED
SSB        LINEORDER            PART_1994       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1995       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1996       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1997       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER            PART_1998       ENABLED    HIGH       AUTO         FOR QUERY LOW
SSB        LINEORDER
SSB        PART                                 DISABLED
SSB        SUPPLIER                             DISABLED25 rows selected.SQL>
SQL> set echo offSQL> @16_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  where owner not in ('AUDSYS','SYS')5  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      478,281,728                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      478,281,728                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      479,330,304                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      280,690,688                0SQL>
SQL> select * from v$inmemory_area;POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
-------------------------- ----------- ---------- --------------- ----------
1MB POOL                    3252682752 2191523840 DONE                     3
64KB POOL                    201326592    5439488 DONE                     3SQL>
SQL> set echo off

一切如初了。

运行清理脚本以重置热图统计信息,关闭 AIM 并为下一个 Lab 清除 IM 列存储。

SQL> @17_aim-high_cleanup.sql
Connected.System altered.Table altered.Connected.
alter table AIM.MEDTAB2 no inmemory
alter table AIM.SMTAB3 no inmemory
alter table AIM.LRGTAB3 no inmemory
alter table AIM.LRGTAB2 no inmemory
alter table AIM.LRGTAB1 no inmemory
alter table AIM.SMTAB1 no inmemory
alter table AIM.MEDTAB1 no inmemory
alter table AIM.MEDTAB3 no inmemory
alter table AIM.LRGTAB4 no inmemory
alter table AIM.SMTAB2 no inmemory
alter table SSB.SUPPLIER no inmemory
alter table SSB.DATE_DIM no inmemory
alter table SSB.PART no inmemory
alter table SSB.EXT_CUST_BULGARIA no inmemory
alter table SSB.EXT_CUST_NORWAY no inmemory
alter table SSB.CUSTOMER no inmemory
alter table SSB.CHICAGO_DATA no inmemory
alter table SSB.JSON_PURCHASEORDER no inmemory
alter table SSB.J_PURCHASEORDER no inmemory
alter table SSB.LINEORDER no inmemory
alter table SSB.LINEORDER modify partition PART_1994 no inmemory
alter table SSB.LINEORDER modify partition PART_1995 no inmemory
alter table SSB.LINEORDER modify partition PART_1996 no inmemory
alter table SSB.LINEORDER modify partition PART_1997 no inmemory
alter table SSB.LINEORDER modify partition PART_1998 no inmemoryPL/SQL procedure successfully completed.SQL> exec dbms_ilm_admin.CLEAR_HEAT_MAP_ALL;PL/SQL procedure successfully completed.

本实验演示了新的 INMEMORY_AUTOMATIC_LEVEL = HIGH 功能如何工作,以及 AIM 级别高如何启用对 IM 列存储内容的自动管理。 这意味着不再需要尝试找出哪些对象将从填充中获得最大收益。 现在数据库将为您自动完成。

实验 8: In-Memory Arithmetic

实验前,需要执行以下:

. ~/.set-env-db.sh CDB1

进入im-arith目录,登录数据库:

cd /home/oracle/labs/inmemory/im-arith
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

此实验的主要脚本执行序列如下,后面会详述:

01_pre_arith.sql
02_im_usage.sql
03_enable_arith.sql
04_im_populated.sql
05_im_usage.sql
06_im_arith.sql

在运行以下实验之前,请确保SSB schema的5张表均已发布成功。如果没有发布,您可以执行setup目录下的以下脚本:

@04_im_alter_table.sql
@06_im_start_pop.sql
@08_im_populated.sql

在启用inmemory arithmetic前,运行脚本:

SQL> @01_pre_arith.sql
-- 耗时
Elapsed: 00:00:04.67-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |  4698 (100)|          |       |       |
|   1 |  SORT AGGREGATE              |           |     1 |    15 |            |          |       |       |
|   2 |   PARTITION RANGE ALL        |           |    41M|   597M|  4698  (32)| 00:00:01 |     1 |     5 |
|   3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|   597M|  4698  (32)| 00:00:01 |     1 |     5 |
------------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            489
IM scan CUs columns accessed                                        234
IM scan CUs memcompress for query low                                78
IM scan CUs pcode aggregation pushdown                              156
IM scan rows                                                   41760941
IM scan rows pcode aggregated                                  41760941
IM scan rows projected                                               78
IM scan rows valid                                             41760941
session logical reads                                            324181
session logical reads - IM                                       315483
session pga memory                                             19973768
table scans (IM)                                                      512 rows selected.

查看内存使用情况:

SQL> @02_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS                          CON_ID
---------- -------------------- -------------------- -------------------------- --------------------
1MB POOL          3,252,682,752        2,234,515,456 DONE                                          3
64KB POOL           201,326,592            6,029,312 DONE                                          3

启用inmemory arithmetic,需要重新发布:

SQL> @03_enable_arith.sql
Connected.
SQL>
SQL> -- This script will enable In-Memory optimized arithmetic
SQL>
SQL> alter table lineorder no inmemory;Table altered.SQL> alter table part      no inmemory;Table altered.SQL> alter table supplier  no inmemory;Table altered.SQL> alter table date_dim  no inmemory;Table altered.SQL>
SQL> alter system set inmemory_optimized_arithmetic = 'ENABLE' scope=both;System altered.SQL>
SQL> alter table LINEORDER inmemory memcompress for query low;Table altered.SQL> alter table PART      inmemory memcompress for query low;Table altered.SQL> alter table SUPPLIER  inmemory memcompress for query low;Table altered.SQL> alter table DATE_DIM  inmemory memcompress for query low;Table altered.SQL>
SQL> select /*+ full(LINEORDER) noparallel(LINEORDER) */ count(*) from LINEORDER;COUNT(*)
--------------------41760941SQL> select /*+ full(PART) noparallel(PART) */ count(*) from PART;COUNT(*)
--------------------800000SQL> select /*+ full(CUSTOMER) noparallel(CUSTOMER) */ count(*) from CUSTOMER;COUNT(*)
--------------------300000SQL> select /*+ full(SUPPLIER) noparallel(SUPPLIER) */ count(*) from SUPPLIER;COUNT(*)
--------------------20000SQL> select /*+ full(DATE_DIM) noparallel(DATE_DIM) */ count(*) from DATE_DIM;COUNT(*)
--------------------2556

确认发布完成:

SQL> @04_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      590,479,360                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      585,236,480                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      587,333,632                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      585,236,480                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      342,556,672                0
SSB        PART                                 COMPLETED             56,893,440       20,119,552                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                09 rows selected.

查看内存使用情况:

SQL> @05_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS               CON_ID
---------- -------------------- -------------------- --------------- --------------------
1MB POOL          3,252,682,752        2,731,540,480 DONE                               3
64KB POOL           201,326,592            6,029,312 DONE                               3

多用了近500M内存:

2,731,540,480-2,234,515,456=497,025,024

重新执行查询,性能提升18%,不算太明显(之前为4.67秒)

SQL> @06_im_arith.sql
-- 耗时
Elapsed: 00:00:03.97-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |  4698 (100)|          |       |       |
|   1 |  SORT AGGREGATE              |           |     1 |    15 |            |          |       |       |
|   2 |   PARTITION RANGE ALL        |           |    41M|   597M|  4698  (32)| 00:00:01 |     1 |     5 |
|   3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|   597M|  4698  (32)| 00:00:01 |     1 |     5 |
------------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            400
IM scan CUs columns accessed                                        234
IM scan CUs memcompress for query low                                78
IM scan CUs pcode aggregation pushdown                              156
IM scan rows                                                   41760941
IM scan rows pcode aggregated                                  41760941
IM scan rows projected                                               78
IM scan rows valid                                             41760941
session logical reads                                            315714
session logical reads - IM                                       315483
session pga memory                                             18483504
table scans (IM)                                                      512 rows selected.

最后,重置参数为默认值:

SQL> alter system set inmemory_optimized_arithmetic = 'DISABLE' scope=both;System altered.

实验 9: In-Memory Hybrid Scan

实验前,需要执行以下:

. ~/.set-env-db.sh CDB1

进入hybrid-scans目录,登录数据库:

cd /home/oracle/labs/inmemory/hybrid-scans
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

调整显示:

set pages 9999
set lines 150

此实验的主要脚本执行序列如下,后面会详述:

01_pop_lineorder.sql
02_im_populated.sql
03_im_query.sql
04_pop_excluded.sql
05_im_populated.sql
06_im_columns.sql
07_hybrid_query.sql
08_hybrid_cleanup.sql

因为查询仅针对1996年的分区,因此先仅发布表的这个分区:

SQL> @01_pop_lineorder.sql
Connected.
SQL>
SQL> alter table lineorder no inmemory;Table altered.SQL>
SQL> alter table lineorder modify partition part_1996 inmemory;Table altered.SQL>
SQL> exec dbms_inmemory.populate(USER, 'LINEORDER', 'PART_1996');PL/SQL procedure successfully completed.SQL>
SQL> set echo off

查看发布状态:

SQL> @02_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      480,378,880                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                0

在未完全发布LINEORDER时,执行查询:

SQL> @03_im_query.sql-- 耗时
Elapsed: 00:00:00.08-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |   727 (100)|          |       |       |
|   1 |  SORT AGGREGATE              |           |     1 |    28 |            |          |       |       |
|   2 |   PARTITION RANGE SINGLE     |           |   999 | 27972 |   727   (4)| 00:00:01 |     3 |     3 |
|*  3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |   999 | 27972 |   727   (4)| 00:00:01 |     3 |     3 |
----------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - inmemory(("LO_ORDERDATE"=TO_DATE(' 1996-01-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND"LO_QUANTITY">40 AND "LO_SHIPMODE"='AIR'))filter(("LO_ORDERDATE"=TO_DATE(' 1996-01-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND"LO_QUANTITY">40 AND "LO_SHIPMODE"='AIR'))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                             25
IM scan CUs columns accessed                                         68
IM scan CUs memcompress for query low                                17
IM scan CUs pcode aggregation pushdown                               17
IM scan rows                                                    9126362
IM scan rows pcode aggregated                                       749
IM scan rows projected                                               17
IM scan rows valid                                              9126362
IM scan segments minmax eligible                                     17
physical reads                                                        9
session logical reads                                             79109
session logical reads - IM                                        68972
session pga memory                                             19728688
table scans (IM)                                                      114 rows selected.

排除掉一些列,这些列中包含了查询涉及的列:

SQL> @04_pop_excluded.sql
Connected.
SQL>
SQL> alter table lineorder no inmemory;Table altered.SQL>
SQL> alter table lineorder2    no inmemory (LO_ORDERPRIORITY,LO_SHIPPRIORITY,LO_EXTENDEDPRICE,LO_ORDTOTALPRICE,3    LO_DISCOUNT,LO_REVENUE,LO_SUPPLYCOST,LO_TAX,LO_COMMITDATE);Table altered.SQL>
SQL> alter table lineorder modify partition part_1996 inmemory;Table altered.SQL>
SQL> exec dbms_inmemory.populate(USER, 'LINEORDER', 'PART_1996');PL/SQL procedure successfully completed.

查看发布状态:

SQL> @05_im_populated.sql
SQL> @../imlogin.sql
SQL> connect ssb/Ora_DB4U@pdb1
Connected.
SQL>
SQL> set pages 9999
SQL> set lines 150
SQL> column owner format a10;
SQL> column segment_name format a20;
SQL> column partition_name format a15;
SQL> column populate_status format a15;
SQL> column bytes heading 'Disk Size' format 999,999,999,999
SQL> column inmemory_size heading 'In-Memory|Size' format 999,999,999,999
SQL> column bytes_not_populated heading 'Bytes|Not Populated' format 999,999,999,999
SQL> set echo on
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      214,040,576                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                0

由于排除了一些列,因此内存的占用由480,378,880下降到214,040,576,减少约266M。

查看列的发布情况:

SQL> @06_im_columns.sql
Connected.
SQL>
SQL> select owner, table_name, COLUMN_NAME, INMEMORY_COMPRESSION2  from v$im_column_level3  where table_name = 'LINEORDER'4  order by table_name, segment_column_id;OWNER      TABLE_NAME           COLUMN_NAME          INMEMORY_COMPRESSION
---------- -------------------- -------------------- --------------------------
SSB        LINEORDER            LO_ORDERKEY          DEFAULT
SSB        LINEORDER            LO_LINENUMBER        DEFAULT
SSB        LINEORDER            LO_CUSTKEY           DEFAULT
SSB        LINEORDER            LO_PARTKEY           DEFAULT
SSB        LINEORDER            LO_SUPPKEY           DEFAULT
SSB        LINEORDER            LO_ORDERDATE         DEFAULT
SSB        LINEORDER            LO_ORDERPRIORITY     NO INMEMORY
SSB        LINEORDER            LO_SHIPPRIORITY      NO INMEMORY
SSB        LINEORDER            LO_QUANTITY          DEFAULT
SSB        LINEORDER            LO_EXTENDEDPRICE     NO INMEMORY
SSB        LINEORDER            LO_ORDTOTALPRICE     NO INMEMORY
SSB        LINEORDER            LO_DISCOUNT          NO INMEMORY
SSB        LINEORDER            LO_REVENUE           NO INMEMORY
SSB        LINEORDER            LO_SUPPLYCOST        NO INMEMORY
SSB        LINEORDER            LO_TAX               NO INMEMORY
SSB        LINEORDER            LO_COMMITDATE        NO INMEMORY
SSB        LINEORDER            LO_SHIPMODE          DEFAULT17 rows selected.

再次执行查询:

SQL> @07_hybrid_query.sql
-- 耗时
Elapsed: 00:00:00.02-- 执行计划
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |           |       |       | 19067 (100)|          |       |       |
|   1 |  SORT AGGREGATE                       |           |     1 |    28 |            |          |       |       |
|   2 |   PARTITION RANGE SINGLE              |           |   999 | 27972 | 19067   (2)| 00:00:01 |     3 |     3 |
|*  3 |    TABLE ACCESS INMEMORY FULL (HYBRID)| LINEORDER |   999 | 27972 | 19067   (2)| 00:00:01 |     3 |     3 |
-------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - filter(("LO_ORDERDATE"=TO_DATE(' 1996-01-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND"LO_QUANTITY">40 AND "LO_SHIPMODE"='AIR'))-- 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                              5
IM scan CUs columns accessed                                         51
IM scan CUs memcompress for query low                                17
IM scan rows                                                    9126362
IM scan rows valid                                              9126362
session logical reads                                             69823
session logical reads - IM                                        68972
session pga memory                                             18155824
table scans (IM)                                                      19 rows selected.

注意执行计划中的第3行:TABLE ACCESS INMEMORY FULL (HYBRID)
怎么感觉性能还变快了?

最后执行清理:

alter table lineorder no inmemory;
alter table lineorder inmemory;
exec dbms_inmemory.populate(USER, 'LINEORDER');

实验 10: In-Memory Expression

实验前,需要执行以下:

. ~/.set-env-db.sh CDB1

进入ime目录,登录数据库:

cd /home/oracle/labs/inmemory/ime
sqlplus ssb/Ora_DB4U@localhost:1521/pdb1

此实验的主要脚本执行序列如下,后面会详述:

01_pre_ime.sql
02_im_usage.sql
03_create_ime.sql
04_im_populated.sql
05_ime_usage.sql
06_im_usage.sql
07_post_ime.sql
08_ime_ess.sql

在实验前,请确保lineorder表已发布。

在启用IME前,执行查询

SQL> @01_pre_ime.sql-- 耗时
Elapsed: 00:00:04.64-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |  5113 (100)|          |       |       |
|   1 |  HASH GROUP BY               |           |     7 |   161 |  5113  (38)| 00:00:01 |       |       |
|   2 |   PARTITION RANGE ALL        |           |    41M|   916M|  5112  (38)| 00:00:01 |     1 |     5 |
|   3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|   916M|  5112  (38)| 00:00:01 |     1 |     5 |
------------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            466
IM scan CUs columns accessed                                        312
IM scan CUs memcompress for query low                                78
IM scan CUs pcode aggregation pushdown                              156
IM scan rows                                                   41760941
IM scan rows pcode aggregated                                  41760941
IM scan rows projected                                              546
IM scan rows valid                                             41760941
session logical reads                                            315641
session logical reads - IM                                       315483
session pga memory                                             18155824
table scans (IM)                                                      512 rows selected.

查看内存使用情况:

SQL> @02_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS                          CON_ID
---------- -------------------- -------------------- -------------------------- --------------------
1MB POOL          3,252,682,752        2,234,515,456 DONE                                          3
64KB POOL           201,326,592            6,029,312 DONE                                          3SQL>
SQL> set echo off

创建inmemory expression:

SQL> @03_create_ime.sql
Connected.
SQL>
SQL> -- Create In-Memory Column Expression
SQL>
SQL> alter table lineorder no inmemory;Table altered.SQL> alter table lineorder add v1 invisible as (lo_ordtotalprice - (lo_ordtotalprice*(lo_discount/100)) + lo_tax);Table altered.SQL> alter table lineorder inmemory;Table altered.SQL> select count(*) from lineorder;COUNT(*)
--------------------41760941

查看发布情况:

SQL> @04_im_populated.sql
Connected.
SQL>
SQL> -- Query the view v$IM_SEGMENTS to shows what objects are in the column store
SQL> -- and how much of the objects were populated. When the BYTES_NOT_POPULATED is 0
SQL> -- it indicates the entire table was populated.
SQL>
SQL> select owner, segment_name, partition_name, populate_status, bytes,2         inmemory_size, bytes_not_populated3  from   v$im_segments4  order by owner, segment_name, partition_name;In-Memory            Bytes
OWNER      SEGMENT_NAME         PARTITION_NAME  POPULATE_STATUS        Disk Size             Size    Not Populated
---------- -------------------- --------------- --------------- ---------------- ---------------- ----------------
SSB        CUSTOMER                             COMPLETED             24,928,256       23,199,744                0
SSB        DATE_DIM                             COMPLETED                122,880        1,179,648                0
SSB        LINEORDER            PART_1994       COMPLETED            563,609,600      626,130,944                0
SSB        LINEORDER            PART_1995       COMPLETED            563,470,336      607,256,576                0
SSB        LINEORDER            PART_1996       COMPLETED            565,018,624      678,559,744                0
SSB        LINEORDER            PART_1997       COMPLETED            563,322,880      614,596,608                0
SSB        LINEORDER            PART_1998       COMPLETED            329,015,296      353,042,432                0
SSB        PART                                 COMPLETED             56,893,440       16,973,824                0
SSB        SUPPLIER                             COMPLETED              1,769,472        2,228,224                09 rows selected.

查看inmemory expression的空间使用情况:

SQL> @05_ime_usage.sql
Connected.
SQL>
SQL> -- This query displays IMEUs populated in the In-Memory Column Store
SQL>
SQL> select2    o.owner,3    o.object_name,4    o.subobject_name as partition_name,5    i.column_name,6    count(*) t_imeu,7    sum(i.length)/1024/1024 space8  from9    v$im_imecol_cu i,10    dba_objects o11  where12    i.objd = o.object_id13  group by14    o.owner,15    o.object_name,16    o.subobject_name,17    i.column_name;Partition            Column            Total         Used
Owner      Object               Name                 Name              IMEUs    Space(MB)
---------- -------------------- -------------------- --------------- ------- ------------
SSB        LINEORDER            PART_1998            V1                   10           62
SSB        LINEORDER            PART_1997            V1                   17          105
SSB        LINEORDER            PART_1996            V1                   17          106
SSB        LINEORDER            PART_1995            V1                   17          105
SSB        LINEORDER            PART_1994            V1                   17          106

查看内存使用情况:

SQL> @06_im_usage.sql
Connected.
SQL> column pool format a10;
SQL> column alloc_bytes format 999,999,999,999,999
SQL> column used_bytes format 999,999,999,999,999
SQL>
SQL> -- Show total column store usage
SQL>
SQL> SELECT pool, alloc_bytes, used_bytes, populate_status, con_id2  FROM   v$inmemory_area;POOL                ALLOC_BYTES           USED_BYTES POPULATE_STATUS               CON_ID
---------- -------------------- -------------------- --------------- --------------------
1MB POOL          3,252,682,752        2,917,138,432 DONE                               3
64KB POOL           201,326,592            6,029,312 DONE                               3

由于有内存表达式,因此内存消耗上涨了约650M。(2,917,138,432 - 2,234,515,456 = 682,622,976)

感觉没有完全对上,前面显示消耗为483M。

启用IME后,运行查询:

SQL> @07_post_ime.sql
-- 耗时
Elapsed: 00:00:01.45-- 执行计划
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |       |       |  5343 (100)|          |       |       |
|   1 |  HASH GROUP BY               |           |     7 |   210 |  5343  (40)| 00:00:01 |       |       |
|   2 |   PARTITION RANGE ALL        |           |    41M|  1194M|  5342  (40)| 00:00:01 |     1 |     5 |
|   3 |    TABLE ACCESS INMEMORY FULL| LINEORDER |    41M|  1194M|  5342  (40)| 00:00:01 |     1 |     5 |
------------------------------------------------------------------------------------------------------------ 会话统计信息
NAME                                                              VALUE
-------------------------------------------------- --------------------
CPU used by this session                                            171
IM scan CUs columns accessed                                        312
IM scan CUs memcompress for query low                                78
IM scan CUs pcode aggregation pushdown                              156
IM scan EU rows                                                41760941
IM scan EUs columns accessed                                         78
IM scan EUs memcompress for query low                                78
IM scan rows                                                   41760941
IM scan rows pcode aggregated                                  41760941
IM scan rows projected                                              546
IM scan rows valid                                             41760941
session logical reads                                            325856
session logical reads - IM                                       315483
session pga memory                                             19990832
table scans (IM)                                                      515 rows selected.

注意会话统计信息中的IM scan EU关键字。

查看Expression Statistics Store (ESS)的使用情况:

SQL> @08_ime_ess.sql
Connected.
SQL>
SQL> -- Expression Statistics Store query
SQL>
SQL> col owner format a6;
SQL> col table_name format a15;
SQL> col expression_text format a70;
SQL> col evaluation_count format 9999999999999999;
SQL>
SQL> select2  --  owner,3    table_name,4  --  expression_id,5    evaluation_count,6    fixed_cost,7    expression_text8  from9    dba_expression_statistics10  where11    owner = 'SSB' and12    table_name = 'LINEORDER' and13    snapshot = 'LATEST'14  order by15    evaluation_count desc;TABLE_NAME       EVALUATION_COUNT                FIXED_COST EXPRESSION_TEXT
--------------- ----------------- ------------------------- ----------------------------------------------------------------------
LINEORDER                41762785   .0000000551081878534547 "LO_REVENUE"
LINEORDER                41762345   .0000000551081878534547 "LO_DISCOUNT"
LINEORDER                41761253      .0000110216375706909 "LO_ORDTOTALPRICE"-"LO_ORDTOTALPRICE"*("LO_DISCOUNT"/100)
LINEORDER                40465966   .0000000551081878534547 "LO_ORDTOTALPRICE"
LINEORDER                    3170   .0000000551081878534547 "LO_SHIPMODE"
LINEORDER                    1638      .0000137770469633637 "LO_ORDTOTALPRICE"-"LO_ORDTOTALPRICE"*("LO_DISCOUNT"/100)+"LO_TAX"
LINEORDER                    1532   .0000000551081878534547 "LO_ORDERDATE"
LINEORDER                    1517   .0000000551081878534547 "LO_QUANTITY"
LINEORDER                    1092   .0000000551081878534547 "LO_TAX"9 rows selected.SQL>
SQL> --
SQL> -- Use the following to capture IM Expressions:
SQL> -- dbms_inmemory_admin.ime_capture_expressions('CURRENT');
SQL> --
SQL> set echo off

The Expression Statistics Store (ESS) is a repository maintained by the optimizer to store statistics about expression evaluation. The ESS resides in the SGA and persists on disk.

最后,执行清理:

alter table lineorder drop column v1;

Oracle 21版Database In-Memory LivaLabs实验(上)相关推荐

  1. oracle 11g duplicate database基于备份复制数据库(四)

    不使用目标数据库的基于备份的复制,下面测试将原数据库使用备份复制到远程主机不同目录 1.对原数据库生成备份 RMAN> backup as compressed backupset databa ...

  2. oracle 11g duplicate database基于备份复制数据库(三)

    不使用目标数据库的基于备份的复制,下面测试将原数据库使用备份复制到远程主机相同目录 1.对原数据库生成备份 RMAN> backup as compressed backupset databa ...

  3. oracle 11g duplicate database基于备份复制数据库(一)

    使用目标数据库的基于备份的复制,下面测试将原数据库使用备份复制到远程主机相同目录. 1.对原数据库生成备份 RMAN> backup as compressed backupset databa ...

  4. oracle 11g duplicate database基于备份复制数据库(五)

    不使用目标数据库和恢复目录基于备份的复制,下面测试将原数据库使用备份复制到远程主机相同目录 1.对原数据库生成备份 RMAN> backup as compressed backupset da ...

  5. oracle 11g duplicate database基于备份复制数据库(六)

    不使用目标数据库和恢复目录基于备份的复制,下面测试将原数据库使用备份复制到远程主机不同目录 1.对原数据库生成备份 RMAN> backup as compressed backupset da ...

  6. oracle 11g duplicate database基于备份复制数据库(二)

    使用目标数据库的基于备份的复制,下面测试将原数据库使用备份复制到远程主机不同目录 1.对原数据库生成备份 RMAN> backup as compressed backupset databas ...

  7. Oracle LiveLabs DB Security (数据库安全)实验汇总

    在Oracle LiveLabs中,和数据库安全相关的实验分为2个系列,共12个实验. Oracle数据库安全架构如下图: 这些实验涉及了Oracle安全相关的特性,企业版选件,独立产品和服务. 关于 ...

  8. EDB PPAS(Oracle 兼容版) Oracle与PostgreSQL 兼容模式的参数配置切换

    标签 PostgreSQL , EDB , PPAS , 参数 , Oracle模式 , PostgreSQL模式 背景 EDB PPAS是EDB推出的一款同时兼容Oracle和PostgreSQL协 ...

  9. Oracle复习(知识点、练习题、实验)

    文章目录 第一章 数据库概念 数据库的三级模式结构:模式.外模式.内模式 三级模式之间的映射 第二章 Oracle12g体系结构 Oracle的逻辑存储结构 Oracle物理存储结构 Oracle11 ...

最新文章

  1. 那还剩下多少学习激情?
  2. 机器学习与高维信息检索 - Note 7 - 核主成分分析(Kernel Principal Component Analysis,K-PCA)
  3. python优秀程序员条件_Python 条件语句
  4. clion opencv安装_Clion+Opencv3.2终极配置教程
  5. 一篇文章学习Python中的多进程
  6. 通过printf从目标板到调试器的输出
  7. SVG 教程 (四)多边形,曲线,路径
  8. 软考网络工程师学习笔记4-局域网与城域网
  9. Internal Error 2738 - Installing ArcGIS Server 9.3,10 for Java
  10. IBM HMC V7R740虚拟机安装实战
  11. 基于嵌入式系统的gnash最小库依赖关系
  12. 从物理页面的争抢看linux内核内存管理
  13. 浙江计算机二级c语言考试,浙江计算机二级考试(C语言)上机试题
  14. 话单数据仓库搭建(1)- 数仓概念及数据采集
  15. 【练习/Python】监测汇率脚本
  16. 刘墉写给女儿的 忠告
  17. 编程实用工具大全(二)(前后端皆可用,不来看看?)
  18. 腾讯云4核8G服务器S5.LARGE8性能测评
  19. iphone游戏广告加载失败_iphone玩游戏怎么不弹广告
  20. 用Python编写一个ISBN查询工具,秒查图书信息

热门文章

  1. Docker容器技术 笔记
  2. 设置centos7.3的YUM源为国内阿里云源
  3. 每周一品 · 扬声器(喇叭)中的磁性材料
  4. 002如何构建hadoop集群环境?
  5. mysql mpp_MPP调研
  6. WordPress网站Logo
  7. ora-27100产生的原因分析
  8. 玩安卓从 0 到 1 之项目总结
  9. Google 后 Hadoop 时代的新 “三驾马车” -- Caffeine(搜索)、Pregel(图计算)、Dremel(查询)
  10. 用DIV+CSS技术设计的网页与实现制作【体育文化】dreamweaver学生网页设计