Oracle 18c新特性-MemOptimized RowStore
Oracle Database 18c中引入的MemOptimized RowStore,該功能可以提高通過主鍵列訪問資料的查詢效能。比如我們經常使用的這樣的SQL語句:SELECT value FROM t WHERE key=:key,其中key是表中的唯一主鍵。
1.Memoptimize Buffer Area
這是表塊的專用緩衝區快取,memoptimized Pool的75%是為此緩衝區快取保留的。
2.Hash Index
雜湊索引就是在記憶體區域做的一個對映表,主鍵就是對映鍵,並且指向Memoptimize Buffer Area中的塊。雜湊索引使用memoptimized Pool的另外25%。
如下圖所示:
資料庫執行SQL語句的時候,將會繞過SQL層,利用記憶體中的雜湊索引直接訪問所需的資料。減少了物理訪問,避免了磁碟I/O。memoptimized pool的大小由初始化引數MEMOPTIMIZE_POOL_SIZE定義的。預設大小是0。更改值需要重新啟動資料庫。最小尺寸是100M。
使用MemOptimized RowStore必須滿足以下條件:
1.該表是堆組織表。
2.該表上有一個主鍵。
3.該表未壓縮。
開啟該功能,會出現一些新的等待事件,總共有65個。如下所示:
SQL> select * from v$statname where name like '%memopt%'; STATISTIC# NAMECLASSSTAT_ID DISPLAY_NAMECON_ID ---------- ---------------------------------------------------------------- ---------- ---------- ---------------------------------------------------------------- ---------- 1682 memopt r fail to pin buffer128311744847 memopt r fail to pin buffer1 1683 memopt r entries deleted128 1246583635 memopt r entries deleted1 1684 memopt r lookups128 2449760253 memopt r lookups1 1685 memopt r hits128 2704996161 memopt r hits1 1686 memopt r misses128 2658693813 memopt r misses1 1687 memopt r tag collisions128 1615233916 memopt r tag collisions1 1688 memopt r lookup skipped deleted rows128 4063719983 memopt r lookup skipped deleted rows1 1689 memopt r lookup skipped locked rows128 1501413709 memopt r lookup skipped locked rows1 1690 memopt r lookup skipped chained rows128 2134479771 memopt r lookup skipped chained rows1 1691 memopt r failed reads on buckets128 2119256684 memopt r failed reads on buckets1 1692 memopt r failed reads on blocks128 3038931328 memopt r failed reads on blocks1 1693 memopt r lookup detected CR buffer128 2118516459 memopt r lookup detected CR buffer1 1694 memopt r puts12812188864 memopt r puts1 1695 memopt r puts:buckets full128860399351 memopt r puts:buckets full1 1696 memopt r successful puts128 2284911377 memopt r successful puts1 1697 memopt r successful puts:with evictions128835169295 memopt r successful puts:with evictions1 1698 memopt r successful puts:with cuckoo128 3118361144 memopt r successful puts:with cuckoo1 1699 memopt r successful puts:cuckoo deadend128 4283018875 memopt r successful puts:cuckoo deadend1 1700 memopt r successful puts:max cuckoo128606780851 memopt r successful puts:max cuckoo1 1701 memopt r failed puts128141088098 memopt r failed puts1 1702 memopt r failed puts:bucket in flux128 1843422109 memopt r failed puts:bucket in flux1 1703 memopt r failed puts:no space128 2311881927 memopt r failed puts:no space1 1704 memopt r populate tasks accepted128 3727334836 memopt r populate tasks accepted1 1705 memopt r populate tasks not accepted128236934488 memopt r populate tasks not accepted1 1706 memopt r populate skipped locked rows128 3833166773 memopt r populate skipped locked rows1 1707 memopt r populate skipped deleted rows128 2993279601 memopt r populate skipped deleted rows1 1708 memopt r populate skipped chained rows128 3189475334 memopt r populate skipped chained rows1 1709 memopt r rows populated128 2576444784 memopt r rows populated1 1710 memopt r populate128 1331937481 memopt r populate1 1711 memopt r blocks populated12899459750 memopt r blocks populated1 1712 memopt r failed to get tbs drop EQ128 2581303612 memopt r failed to get tbs drop EQ1 1713 memopt r failed to get tbs offline EQ128 4132756765 memopt r failed to get tbs offline EQ1 1714 memopt r failed to get segment drop EQ128 2711296718 memopt r failed to get segment drop EQ1 1715 memopt r repopulate tasks accepted12855882086 memopt r repopulate tasks accepted1 1716 memopt r repopulate tasks not accepted128308832077 memopt r repopulate tasks not accepted1 1717 memopt r repopulate128 4292673878 memopt r repopulate1 1718 memopt r rows repopulated128412578977 memopt r rows repopulated1 1719 memopt r blocks repopulated128 4086731426 memopt r blocks repopulated1 1720 memopt r repopulate skipped locked rows128 1039941343 memopt r repopulate skipped locked rows1 1721 memopt r repopulate skipped deleted rows128 1453092269 memopt r repopulate skipped deleted rows1 1722 memopt r repopulate skipped chained rows128 1283143522 memopt r repopulate skipped chained rows1 1723 memopt r repopulate invalidated entries128 2406172163 memopt r repopulate invalidated entries1 1724 memopt r cleanup1281970750 memopt r cleanup1 1725 memopt r NO IM tasks accepted128 1465237793 memopt r NO IM tasks accepted1 1726 memopt r NO IM tasks not accepted128 3768980909 memopt r NO IM tasks not accepted1 1727 memopt r DROP IM tasks accepted128 2574115598 memopt r DROP IM tasks accepted1 1728 memopt r DROP IM tasks not accepted128 2139934761 memopt r DROP IM tasks not accepted1 1729 memopt w buffer gets128944697423 memopt w buffer gets1 1730 memopt w rows written128 3945680858 memopt w rows written1 1731 memopt w rows flushed128 1806100090 memopt w rows flushed1 1732 memopt w flush tasks128945910151 memopt w flush tasks1 1733 memopt w flush tasks deferred128 2737332709 memopt w flush tasks deferred1 1734 memopt w buffer miss space128 2208213025 memopt w buffer miss space1 1735 memopt w buffer miss latch128 3552849954 memopt w buffer miss latch1 1736 memopt w buffer miss waits128315661965 memopt w buffer miss waits1 1737 memopt w buffer miss spc nolatch128 1789953959 memopt w buffer miss spc nolatch1 1738 memopt w buffer miss wait unq128196625028 memopt w buffer miss wait unq1 1739 memopt w buffer gotcur128 3639906483 memopt w buffer gotcur1 1740 memopt w buffer miss spc unq nolat128 3892484010 memopt w buffer miss spc unq nolat1 1741 memopt w buffer miss nobuf128 1059644383 memopt w buffer miss nobuf1 1742 memopt w buffer hit bucket 0128 1458260122 memopt w buffer hit bucket 01 1743 memopt w buffer wake post128 1524849321 memopt w buffer wake post1 1744 memopt w drain sleep work128 3595850574 memopt w drain sleep work1 1745 memopt w drain sleep128 1578572087 memopt w drain sleep1 1746 memopt w drain sleep wake post128 2681285354 memopt w drain sleep wake post1
下面我們就來做一些測試。
1.首先需要調整memoptimize_pool_size引數.
ALTER SYSTEM SET memoptimize_pool_size = 200M SCOPE=SPFILE; SHUTDOWN IMMEDIATE STARTUP
2.建立表並插入資料
CREATE TABLE t1 ( keyINTEGERNOT NULL, valueVARCHAR2(20)NOT NULL, CONSTRAINT pk_key PRIMARY KEY (key) ) SQL> insert into t1 select rownum,'value'||to_char(rownum) from dual connect by level<=1000000; 1000000 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('SYS','T1'); PL/SQL procedure successfully completed.
3.啟用MemOptimized RowStore,建立hash index
SQL> alter table t1 memoptimize for read; Table altered. SQL> exec dbms_memoptimize.populate(schema_name=>'SYS',table_name=>'T1'); PL/SQL procedure successfully completed.
4.執行查詢,檢視執行計劃
SQL> set linesize 175 pagesize 1000 SQL> set autotrace traceonly SQL> SELECT * FROM t1 WHERE key = 99; Execution Plan ---------------------------------------------------------- Plan hash value: 3650286101 ------------------------------------------------------------------------------------------------- | Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time| ------------------------------------------------------------------------------------------------- |0 | SELECT STATEMENT||1 |17 |3(0)| 00:00:01 | |1 |TABLE ACCESS BY INDEX ROWID READ OPTIM| T1|1 |17 |3(0)| 00:00:01 | |*2 |INDEX UNIQUE SCAN READ OPTIM| PK_KEY |1 ||2(0)| 00:00:01 | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("KEY"=99) Statistics ---------------------------------------------------------- 14recursive calls 0db block gets 22consistent gets 0physical reads 0redo size 628bytes sent via SQL*Net to client 623bytes received via SQL*Net from client 2SQL*Net roundtrips to/from client 3sorts (memory) 0sorts (disk) 1rows processed
可以看到這裡沒有物理讀,而執行計劃顯示2步分別是“INDEX UNIQUE SCAN READ OPTIM”,“TABLE ACCESS BY INDEX ROWID READ OPTIM”。 我們還可以通過下列查詢來查該操作的一些統計值,再執行一次,memopt r lookups和memopt r hint都增加了。代表這訪問雜湊索引(1 memopt r lookups),找到記憶體的資料,hint命中(memopt r hint)
SQL> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# = b.STATISTIC# and a.CON_ID=b.CON_ID and a.name like '%memopt%' and value<>0; NAMEVALUE ---------------------------------------------------------------- ---------- memopt r lookups3 memopt r hits3 memopt r populate tasks accepted1 SQL> SELECT * FROM t1 WHERE key = 99; KEY VALUE ---------- -------------------- 99 value99 SQL> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# = b.STATISTIC# and a.CON_ID=b.CON_ID and a.name like '%memopt%' and value<>0; NAMEVALUE ---------------------------------------------------------------- ---------- memopt r lookups4 memopt r hits4 memopt r populate tasks accepted1
那麼我們在來看其他幾個例子
1.使用大於或者小於.
SQL> set autotrace ON explain SQL> select * from t1 WHERE key <10; Execution Plan ---------------------------------------------------------- Plan hash value: 1458221975 ---------------------------------------------------------------------------------------------- | Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time| ---------------------------------------------------------------------------------------------- |0 | SELECT STATEMENT||9 |153 |4(0)| 00:00:01 | |1 |TABLE ACCESS BY INDEX ROWID BATCHED| T1|9 |153 |4(0)| 00:00:01 | |*2 |INDEX RANGE SCAN| PK_KEY |9 ||3(0)| 00:00:01 | ---------------------------------------------------------------------------------------------- SQL> set autotrace off SQL> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# = b.STATISTIC# and a.CON_ID=b.CON_ID and a.name like '%memopt%' and value<>0; NAMEVALUE ---------------------------------------------------------------- ---------- memopt r lookups4 memopt r hits4 memopt r populate tasks accepted1
可以看到使用>和 <並沒有使用memoptimized rowstore特性="">
2.使用多個=
SQL> select * from t1 WHERE key=10 or key=11; Execution Plan ---------------------------------------------------------- Plan hash value: 2536766119 --------------------------------------------------------------------------------------- | Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time| --------------------------------------------------------------------------------------- |0 | SELECT STATEMENT||2 |34 |5(0)| 00:00:01 | |1 |INLIST ITERATOR|||||| |2 |TABLE ACCESS BY INDEX ROWID| T1|2 |34 |5(0)| 00:00:01 | |*3 |INDEX UNIQUE SCAN| PK_KEY |2 ||4(0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("KEY"=10 OR "KEY"=11) SQL> select * from t1 WHERE key=10 and key=11; Execution Plan ---------------------------------------------------------- Plan hash value: 3010271221 --------------------------------------------------------------------------------------- | Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time| --------------------------------------------------------------------------------------- |0 | SELECT STATEMENT||1 |17 |0(0)|| |*1 |FILTER|||||| |2 |TABLE ACCESS BY INDEX ROWID| T1|1 |17 |3(0)| 00:00:01 | |*3 |INDEX UNIQUE SCAN| PK_KEY |1 ||2(0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(NULL IS NOT NULL) 3 - access("KEY"=10)
3.使用多個列
SQL> select * from t1 WHERE key=10 and value='value10'; Execution Plan ---------------------------------------------------------- Plan hash value: 3650286101 -------------------------------------------------------------------------------------- | Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time| -------------------------------------------------------------------------------------- |0 | SELECT STATEMENT||1 |17 |3(0)| 00:00:01 | |*1 |TABLE ACCESS BY INDEX ROWID| T1|1 |17 |3(0)| 00:00:01 | |*2 |INDEX UNIQUE SCAN| PK_KEY |1 ||2(0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("VALUE"='value10') 2 - access("KEY"=10)
可以看到,使用其他的條件都不能使用MemOptimized RowStore。
參考文件
https://docs.oracle.com/en/database/oracle/oracle-database/18/cncpt/memory-architecture.html#GUID-D58DC90F-0ABB-4B1E-96C1-6094A04A5E12
https://docs.oracle.com/en/database/oracle/oracle-database/18/tgdba/tuning-system-global-area.html#GUID-4434D082-4748-47C3-A410-B7E2B443DD16