Introduction

About the In-Memory feature

The Oracle Database has a feature known as Database In-Memory, which accelarates analytics workload with an entire table, index, or partition loaded in memory. Starting with 19.8, this feature can be used with Enterprise Edition limited up to 16 GB of memory, which is defined as In-Memory Base Level. To use more than 16 GB or any value in older version, an additional license to use the In-Memory Option is required.

About the In-Memory Advisor

Traditionally Oracle has developed an In-Memory Advisor that can be downloaded from the My Oracle Support (MOS), and installed in the target Database. This old Advisor is the same used by the OEM In-Memory Advisor, and can be installed in any Oracle Database with 11.2.0.3 version or higher, including non-CDB and CDB. Note that the advisor require a Tuning Management pack license.

You can find this old Advisor here.

New with 23ai

Starting with 23ai, a new Advisor was included in the database as a Built-in standard package, so we not need to download and install a separeted package anymore. The new Advisor is implemented in the DBMS_INMEMORY_ADVISE package, which currently have the following procedures and functions:

/* Package SYS.DBMS_INMEMORY_ADVISE */
/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE  */
    SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE(   START_SNAP_ID      =>  p_IN_param0  /*   NUMBER   */,
                                                     END_SNAP_ID        =>  p_IN_param1  /*   NUMBER   */,
                                                     INMEM_ELIGIBLE     =>  p_OUT_param2  /*   BOOLEAN   */,
                                                     ANALYSIS_SUMMARY   =>  p_OUT_param3  /*   VARCHAR2   */,
                                                     SNAP_DBID          =>  p_IN_param4  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE  */
    SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE(   START_TIME         =>  p_IN_param0  /*   TIMESTAMP   */,
                                                     END_TIME           =>  p_IN_param1  /*   TIMESTAMP   */,
                                                     INMEM_ELIGIBLE     =>  p_OUT_param2  /*   BOOLEAN   */,
                                                     ANALYSIS_SUMMARY   =>  p_OUT_param3  /*   VARCHAR2   */,
                                                     SNAP_DBID          =>  p_IN_param4  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE  */
    SYS.DBMS_INMEMORY_ADVISE.IS_INMEMORY_ELIGIBLE(   TIME_WINDOW_DAYS   =>  p_IN_param0  /*   NUMBER   */,
                                                     INMEM_ELIGIBLE     =>  p_OUT_param1  /*   BOOLEAN   */,
                                                     ANALYSIS_SUMMARY   =>  p_OUT_param2  /*   VARCHAR2   */,
                                                     SNAP_DBID          =>  p_IN_param3  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.START_TRACKING  */
    SYS.DBMS_INMEMORY_ADVISE.START_TRACKING(   TASK_ID   =>  p_OUT_param0  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.STOP_TRACKING  */
    SYS.DBMS_INMEMORY_ADVISE.STOP_TRACKING();

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.GENERATE_ADVISE  */
    SYS.DBMS_INMEMORY_ADVISE.GENERATE_ADVISE();

/*  FUNCTION  SYS.DBMS_INMEMORY_ADVISE.LIST_ADVISE  */
    /*   RETURN PL/SQL RECORD   */
     v_ret := SYS.DBMS_INMEMORY_ADVISE.LIST_ADVISE(   TASK_ID         =>  p_IN_param0  /*   NUMBER   */,
                                                      INMEMORY_SIZE   =>  p_IN_param1  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.DROP_TASK  */
    SYS.DBMS_INMEMORY_ADVISE.DROP_TASK(   TASK_ID   =>  p_IN_param0  /*   NUMBER   */);

/*  PROCEDURE  SYS.DBMS_INMEMORY_ADVISE.DROP_OLD_TASKS  */
    SYS.DBMS_INMEMORY_ADVISE.DROP_OLD_TASKS(   DAYS   =>  p_IN_param0  /*   NUMBER   */);

Also, a new dictionary view DBA_INMEMORY_ADVISOR_RECOMMENDATION was introduced, where we can query the tasks results directly using SQL query:

NAME                               DATA TYPE   NULL  DEFAULT    COMMENTS
 TASK_ID                           NUMBER      Yes              IM advisor task id
 INMEMORY_SIZE                     NUMBER      Yes              Simulated IM size
 ESTIMATED_DB_TIME_LOW             NUMBER      Yes              Low end of the predicted DB Time range with IM
 ESTIMATED_DB_TIME_HIGH            NUMBER      Yes              High end of the predicted DB Time range with IM
 ESTIMATED_DB_TIME_ANALYTICS_LOW   NUMBER      Yes              Low end of the predicted DB analytical time range with IM
 ESTIMATED_DB_TIME_ANALYTICS_HIGH  NUMBER      Yes              High end of the predicted DB analytical Time range with IM
 RECOMMENDED_OBJ_LIST              CLOB        Yes              List of recommended objects for the simulated IM size

Get Started

In-Memory Eligibility Test

Before run the Advisor itself, it is a good idea execute an In-Memory Eligibility Test, which is implemented by the IS_INMEMORY_ELIGIBLE procedure. This step executes in just few seconds, evaluates a past database workload using AWR and ASH, and determines if the database is a candidate to use the In-Memory feature.

The following example executes the test considering the last 4 hours of AWR and ASH history:

set serveroutput on;
declare
 inmem_eligible BOOLEAN;
 analysis_summary VARCHAR2(4000);
begin
 dbms_inmemory_advise.is_inmemory_eligible(sysdate-4/24, sysdate, inmem_eligible, analysis_summary);
 DBMS_OUTPUT.PUT_LINE('====================================================================');
 dbms_output.put_line('Is In-Memory Elegible..: ' || to_char(inmem_eligible));
 dbms_output.put_line('Analysis Summary.......: ' || analysis_summary);
 DBMS_OUTPUT.PUT_LINE('====================================================================');
end;
/

Example:

====================================================================
Is In-Memory Elegible..: TRUE
Analysis Summary.......: Observed Analytic Workload Percentage is 97.56% is greater than target Analytic Workload Percentage 20%
====================================================================


PL/SQL procedure successfully completed.

The Eligibility Test resulted in TRUE, indicating that this database can be a good candidate to use In-Memory feature.

TIP: This procedure was included in 19c starting with 19.20 RU.

In-Memory Advisor

Different then In-Memory Eligibility Test that only validates if could be benefical to use In-Memory in this database, the In-Memory Advisor itself executes a detailed analysis of the workload, and generates a list of recommended tables and or partitions that should use In-Memory.

1) First, we need to enable the heap_map feature:

alter system set heat_map=on;

2) Now we can create a Advisor task:

set serveroutput on;
declare
 taskId number;
begin
 DBMS_INMEMORY_ADVISE.START_TRACKING(TASK_ID =>  taskId);
 dbms_output.put_line('Task ID: ' || taskId);
end;
/

The result should be similar to this:

Task ID: 4

PL/SQL procedure successfully completed.

Here you should wait some time while the applications use the database, as the Advisor will observe the live workload.

3) After some time, we can stop the workload tracking:

EXEC DBMS_INMEMORY_ADVISE.STOP_TRACKING();

4) So we can generate the recommendations for the last task:

EXEC DBMS_INMEMORY_ADVISE.GENERATE_ADVISE();

5) Finally, we can get the task results using the LIST_ADVISE function.

The usage of this function can be complex for beginners and the example in the official docs look like incomplete at this time.

I invested some time adapting and testing the below script, which now works fine:

  • In task_id, provide the number returned in step 1.
  • In inmemory_size_mb, provide the size of In-Memory that you intend to configure, or any value that you want to simulate.

In the real world you can need to adjust the script to use GB instead of MB).

/*
  Script to print the In-Memory Advisor report using PL/SQL API (23ai+)
  Maicon Carneiro (dibiei.blog)
  02/04/2025
*/
undef task_id
undef inmemory_size_mb
set serveroutput on;
DECLARE
    v_task_id NUMBER := &task_id;
    v_inmemory_size NUMBER := (&inmemory_size_mb *1024*1024);
    v_ret SYS.DBMS_INMEMORY_ADVISE.INMEMORY_ADVISOR_RECOMMENDATION;
    v_ObjectList varchar2(4000);
BEGIN
    v_ret := SYS.DBMS_INMEMORY_ADVISE.LIST_ADVISE(TASK_ID => v_task_id, INMEMORY_SIZE => v_inmemory_size );
    DBMS_OUTPUT.PUT_LINE('====================================================================');
    DBMS_OUTPUT.PUT_LINE('In-Memory Size (MB)...........: ' || round(v_ret.inmemory_size/1024/1024));
    DBMS_OUTPUT.PUT_LINE('DB Time Baseline..............: ' || v_ret.db_time_baseline);
    DBMS_OUTPUT.PUT_LINE('DB Time Baseline (Analytics)..: ' || v_ret.db_time_baseline_analytics);
    DBMS_OUTPUT.PUT_LINE('DB Time High..................: ' || v_ret.db_time_high);
    DBMS_OUTPUT.PUT_LINE('DB Time Low...................: ' || v_ret.db_time_low);
    DBMS_OUTPUT.PUT_LINE('Analytics Time High...........: ' || v_ret.db_time_analytics_high);
    DBMS_OUTPUT.PUT_LINE('Analytics Time Low............: ' || v_ret.db_time_analytics_low);
    DBMS_OUTPUT.PUT_LINE('');
    DBMS_OUTPUT.PUT_LINE('Recommended tables list.......: ');
    FOR i IN 1 .. v_ret.recommended_obj_list.COUNT LOOP
        v_ObjectList := v_ret.recommended_obj_list(i).Owner || '.' || v_ret.recommended_obj_list(i).Object_Name;
        if (v_ret.recommended_obj_list(i).Subobject_Name is not null) THEN
          v_ObjectList := v_ObjectList || ' (' || v_ret.recommended_obj_list(i).Subobject_Name || ')';
        end if;
        DBMS_OUTPUT.PUT_LINE(v_ObjectList);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('====================================================================');
END;
/

The result should be similar to this:

Enter value for task_id: 4
Enter value for inmemory_size_mb: 100
====================================================================
In-Memory Size (MB)...........: 100
DB Time Baseline..............: 57
DB Time Baseline (Analytics)..: 57
DB Time High..................: 19
DB Time Low...................: 9
Analytics Time High...........: 19
Analytics Time Low............: 9

Recommended tables list.......:
SH.SALES
SH.TIMES
SH.CUSTOMERS
SH.COUNTRIES
SH.CHANNELS
SH.PRODUCTS
====================================================================


PL/SQL procedure successfully completed.

Another option is to query the DBA_INMEMORY_ADVISOR_RECOMMENDATION view:

set sqlformat
set long 99999
SET LINES 400
COL TASK_ID                             HEADING 'Task|ID'  FORMAT 999999
COL INMEMORY_SIZE                       HEADING 'In-Memory|Size (MB)'  FORMAT 999,999,999
COL ESTIMATED_DB_TIME_LOW               HEADING 'Low|Estimated|DB Time'  FORMAT 999999
COL ESTIMATED_DB_TIME_HIGH              HEADING 'High|Estimated|DB Time'  FORMAT 999999
COL ESTIMATED_DB_TIME_ANALYTICS_LOW     HEADING 'Low|Estimated|DB Time Analytics'  FORMAT 999999
COL ESTIMATED_DB_TIME_ANALYTICS_HIGH    HEADING 'High|Estimated|DB Time Analytics'  FORMAT 999999
COL RECOMMENDED_OBJ_LIST                HEADING 'Recommended | Object| List'  FORMAT A100
SELECT TASK_ID,
       INMEMORY_SIZE/1024/1024 INMEMORY_SIZE,
       ESTIMATED_DB_TIME_LOW,
       ESTIMATED_DB_TIME_HIGH,
       ESTIMATED_DB_TIME_ANALYTICS_LOW,
       ESTIMATED_DB_TIME_ANALYTICS_HIGH,
       RECOMMENDED_OBJ_LIST
FROM DBA_INMEMORY_ADVISOR_RECOMMENDATION
WHERE TASK_ID = 4;

Which produces the following result:

                           Low      High               Low              High Recommended
   Task    In-Memory Estimated Estimated         Estimated         Estimated Object
     ID    Size (MB)   DB Time   DB Time DB Time Analytics DB Time Analytics List
------- ------------ --------- --------- ----------------- ----------------- ----------------------------------------------------------------------------------------------------
      4            0        57        57                57                57
      4           21        17        25                17                25 Owner: SH Table: SALES ; Owner: SH Table: TIMES ;
      4           35         9        19                 9                19 Owner: SH Table: SALES ; Owner: SH Table: TIMES ; Owner: SH Table: CUSTOMERS ; Owner: SH Table: COUN
                                                                             TRIES ; Owner: SH Table: CHANNELS ; Owner: SH Table: PRODUCTS ;


3 rows selected.

Alternativelly, I created this version of the query that allow us to filter a specific In-Memory size, and the format of Object List was customized as well:

set sqlformat
set verify off;
set long 99999
SET LINES 400
SET PAGES 100
COL TASK_ID                             HEADING 'Task|ID'  FORMAT 999999
COL INMEMORY_SIZE                       HEADING 'In-Memory|Size (MB)'  FORMAT 999,999,999
COL ESTIMATED_DB_TIME_LOW               HEADING 'Low|Estimated|DB Time'  FORMAT 999999
COL ESTIMATED_DB_TIME_HIGH              HEADING 'High|Estimated|DB Time'  FORMAT 999999
COL ESTIMATED_DB_TIME_ANALYTICS_LOW     HEADING 'Low|Estimated|DB Time Analytics'  FORMAT 999999
COL ESTIMATED_DB_TIME_ANALYTICS_HIGH    HEADING 'High|Estimated|DB Time Analytics'  FORMAT 999999
COL RECOMMENDED_OBJ_LIST                HEADING 'Recommended | Object| List'  FORMAT A50
undef inmemory_size_mb;
SELECT TASK_ID,
       INMEMORY_SIZE/1024/1024 INMEMORY_SIZE,
       ESTIMATED_DB_TIME_LOW,
       ESTIMATED_DB_TIME_HIGH,
       ESTIMATED_DB_TIME_ANALYTICS_LOW,
       ESTIMATED_DB_TIME_ANALYTICS_HIGH,
       REPLACE(REPLACE(REPLACE(RECOMMENDED_OBJ_LIST,'Owner: ',''),' Table: ','.'),' ; ',chr(10)) AS RECOMMENDED_OBJ_LIST
FROM DBA_INMEMORY_ADVISOR_RECOMMENDATION a
WHERE TASK_ID = &task_id
  AND ( nvl('&&inmemory_size_mb',0) = 0 
    OR INMEMORY_SIZE = 
    (SELECT MAX(INMEMORY_SIZE)
       FROM DBA_INMEMORY_ADVISOR_RECOMMENDATION b
      WHERE a.TASK_ID = b.TASK_ID
        AND (INMEMORY_SIZE/1024/1024) <= nvl('&&inmemory_size_mb',0) 
    )
 );

Example for the result for this second query:

Enter value for task_id: 4
Enter value for inmemory_size_mb: 100

                           Low      High               Low              High Recommended
   Task    In-Memory Estimated Estimated         Estimated         Estimated Object
     ID    Size (MB)   DB Time   DB Time DB Time Analytics DB Time Analytics List
------- ------------ --------- --------- ----------------- ----------------- --------------------------------------------------
      4           35         9        19                 9                19 SH.SALES
                                                                             SH.TIMES
                                                                             SH.CUSTOMERS
                                                                             SH.COUNTRIES
                                                                             SH.CHANNELS
                                                                             SH.PRODUCTS


1 row selected.

Another example where the SALES table was partitioned:

Enter value for task_id: 3
Enter value for inmemory_size_mb: 40

                                                           Estimated          Estimated Recommended
   Task     InMemory     Estimated      Estimated  DB Time Analytics  DB Time Analytics Object
     ID         Size DB Time (Low) DB Time (High)              (Low)             (High) List
------- ------------ ------------- -------------- ------------------ ------------------ ----------------------------------------------------------------------------------------------------
      3           37             6              7                  6                  7 SH.SALES Partition: SYS_P1241
                                                                                        SH.SALES Partition: SYS_P1182
                                                                                        SH.SALES Partition: SYS_P1208
                                                                                        SH.SALES Partition: SYS_P1186
                                                                                        SH.SALES Partition: SYS_P1242
                                                                                        SH.SALES Partition: SYS_P1229
                                                                                        SH.SALES Partition: SYS_P1190

Conclusion

In this blog post we demonstrated how to starting to use the In-Memory Advisor available as a new feature in Oracle Database 23ai, which is a great improvement as we don’t need to download and install the Advisor manually. This reduce the complexibility and effort to use this feature, and ensure that the Advisor will be updated automatically as part of the quartely release update.

At this time, I don’t see any option to generate HTML report as we can do in the legacy In-Memory Advisor, but I noticed that the package has been improved in the latest update of Database 23ai FREE instance (23.7.0.25.01), so I believe that we can expect new things in the next updates.

References

https://www.oracle.com/database/technologies/inmemory-advisor.html

https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/DBA_INMEMORY_AIMTASKDETAILS.html

https://docs.oracle.com/en/database/oracle/oracle-database/23/inmem/intro-to-in-memory-column-store.html#GUID-8FCA05F6-8158-42EC-B698-4B20F8983DDF

Leave a Reply

Discover more from Blog do Dibiei

Subscribe now to keep reading and get access to the full archive.

Continue reading