Oracle 19c Automatic Indexing: My First Auto Index (Absolute Beginners) August 19, 2019
Posted by Richard Foote in 19c, 19c New Features, Automatic Indexing, Oracle Indexes.trackback
I am SOOOO struggling with this nightmare block editor but here goes. Please excuse any formatting issues below:
I thought it was time to show the new Oracle 19c Automatic Indexing feature in action and what better way than to go through how I created my first ever Automatic Index.
To start, I create a typically simple little table:
SQL> create table bowie (id number constraint bowie_pk primary key, code number, name varchar2(42)); Table created. SQL> insert into bowie select rownum, mod(rownum, 1000000)+1, 'David Bowie' from dual connect by level commit; Commit complete. SQL> exec dbms_stats.gather_table_stats(ownname=>null, tabname=>'BOWIE'); PL/SQL procedure successfully completed. SQL> select index_name, auto, constraint_index, visibility, compression, status, num_rows, leaf_blocks, clustering_factor from user_indexes where table_name='BOWIE'; INDEX_NAME AUT CON VISIBILIT COMPRESSION STATUS NUM_ROWS LEAF_BLOCKS CLUSTERING_FACTOR ------------------------- --- --- --------- ------------- -------- ---------- ----------- ----------------- BOWIE_PK NO YES VISIBLE DISABLED VALID 10000000 19429 58133
The key column here is CODE, which is highly selective with just 10 rows on average per CODE value.
If I run the following query a number of times:
SQL> select * from bowie where code=42; 10 rows selected. Execution Plan -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 230 | 6208 (7)| 00:00:01 | | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10000 | 10 | 230 | 6208 (7)| 00:00:01 | | 3 | PX BLOCK ITERATOR | | 10 | 230 | 6208 (7)| 00:00:01 | |* 4 | TABLE ACCESS STORAGE FULL | BOWIE | 10 | 230 | 6208 (7)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - storage("CODE"=42) filter("CODE"=42) Statistics ---------------------------------------------------------- 6 recursive calls 0 db block gets 39026 consistent gets 0 physical reads 0 redo size 867 bytes sent via SQL*Net to client 588 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 10 rows processed
The query runs slowly as it performs a Full Table Scan of a 10M row table when returning just 10 runs.
Perhaps an index would be a good idea…
With Auto Indexing, we just wait approx. 15 minutes until the Auto Index task completes, or manually run exec dbms_auto_index_internal.task_proc(true);
As discussed in my previous blog post, the Auto Indexing task will look at the workload over the past 15 minutes and determine if a new index might be warranted to improve the performance of an SQL.
We can query the results of the last Auto Index task by running the following:
SQL> select dbms_auto_index.report_last_activity() report from dual; REPORT -------------------------------------------------------------------------------- GENERAL INFORMATION ------------------------------------------------------------------------------- Activity start : 20-JUN-2019 08:12:15 Activity end : 20-JUN-2019 08:12:55 Executions completed : 1 Executions interrupted : 0 Executions with fatal error : 0 ------------------------------------------------------------------------------- SUMMARY (AUTO INDEXES) ------------------------------------------------------------------------------- Index candidates : 1 Indexes created (visible / invisible) : 1 (1 / 0) Space used (visible / invisible) : 184.55 MB (184.55 MB / 0 B) Indexes dropped : 0 SQL statements verified : 2 SQL statements improved (improvement factor) : 1 (39044.8x) SQL plan baselines created : 0 Overall improvement factor : 6.9x ------------------------------------------------------------------------------- SUMMARY (MANUAL INDEXES) ------------------------------------------------------------------------------- Unused indexes : 0 Space used : 0 B Unusable indexes : 0
At this point in the report, we can see Oracle has verified 2 SQL statements and has created 1 new, visible index using 184.55 MB of space. It has improved 1 SQL statement by a factor of 39044.8x and improved things overall by a factor of 6.9x. (we’ll look at how Oracle determines these values in a later post).
The report continues with the Index Details section:
INDEX DETAILS ------------------------------------------------------------------------------- The following indexes were created: --------------------------------------------------------------------- | Owner | Table | Index | Key | Type | Properties | --------------------------------------------------------------------- | BOWIE | BOWIE | SYS_AI_600vgjmtqsgv3 | CODE | B-TREE | NONE | ---------------------------------------------------------------------
Oracle has decided to create a new indexed called “SYS_AI_600vgjmtqsgv3” on the CODE column of the BOWIE table. Notice the mixed case naming convention for the new Auto Index, oh what fun and games to be had…
Next the Verification Details section:
VERIFICATION DETAILS ------------------------------------------------------------------------------- The performance of the following statements improved: ------------------------------------------------------------------------------- Parsing Schema Name : BOWIE SQL ID : dd5gzx7skf6as SQL Text : select * from bowie where code=42 Improvement Factor : 39044.8x Execution Statistics: ----------------------------- Original Plan Auto Index Plan ---------------------------- ---------------------------- Elapsed Time (s): 3241698 108 CPU Time (s): 3174021 108 Buffer Gets: 663764 13 Optimizer Cost: 6204 14 Disk Reads: 0 0 Direct Writes: 0 0 Rows Processed: 170 10 Executions: 17 1
So the SQL we previously ran has an improvement factor of 39044.8x with the new plan that uses the newly created Auto Index. These numbers are a little nonsensical as we’ll see in a later post, but it does sound kinda impressive…
Finally, we get to the Plans Section of the report:
PLANS SECTION --------------------------------------------------------------------------------------------- - Original ----------------------------- Plan Hash Value : 3567883234 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 6204 | | | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10000 | 425 | 20825 | 6204 | 00:00:01 | | 3 | PX BLOCK ITERATOR | | 425 | 20825 | 6204 | 00:00:01 | | 4 | TABLE ACCESS STORAGE FULL | BOWIE | 425 | 20825 | 6204 | 00:00:01 | ------------------------------------------------------------------------------------- - With Auto Indexes ----------------------------- Plan Hash Value : 493118340 ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 230 | 14 | 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID BATCHED | BOWIE | 10 | 230 | 14 | 00:00:01 | | * 2 | INDEX RANGE SCAN | SYS_AI_600vgjmtqsgv3 | 10 | | 3 | 00:00:01 |
Here Oracle compares the original plan with the new plan that uses the new index. The new plan is much more efficient and so the index is created as a Valid, Visible index.
Note: the vast majority of my test cases were run on the Dedicated Autonomous Application Transaction Processing (ATP) environment, where parallelism is common for most plans by default.
Let’s look at details of the newly created Automatic Index:
SQL> select index_name, auto, constraint_index, visibility, compression, status, num_rows, leaf_blocks, clustering_factor from user_indexes where table_name='BOWIE'; INDEX_NAME AUT CON VISIBILIT COMPRESSION STATUS NUM_ROWS LEAF_BLOCKS CLUSTERING_FACTOR ------------------------- --- --- --------- ------------- -------- ---------- ----------- ----------------- BOWIE_PK NO YES VISIBLE DISABLED VALID 10000000 19429 58133 SYS_AI_600vgjmtqsgv3 YES NO VISIBLE DISABLED VALID 10000000 22419 10000000 SQL> select index_name, column_name, column_position from user_ind_columns where table_name='BOWIE' order by index_name, column_position; INDEX_NAME COLUMN_NAME COLUMN_POSITION ------------------------- -------------------- --------------- BOWIE_PK ID 1 SYS_AI_600vgjmtqsgv3 CODE 1
There is new column column called AUTO in DBA_INDEXES to denote where an index has been automatically created by Oracle.
So the new SYS_AI_600vgjmtqsgv3 Automatic Index on the CODE column is both VISIBLE and VALID in this case, meaning it can be globally used within the database. As we’ll see if future posts, this is not always the case with Automatic Indexes.
If we now re-run the initial SQL query I ran and look at the execution plan:
SQL> select * from bowie where code=42; 10 rows selected. Execution Plan -------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 230 | 13 (0)| 00:00:01 | | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | 10 | 230 | 13 (0)| 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID BATCHED| BOWIE | 10 | 230 | 13 (0)| 00:00:01 | | 4 | BUFFER SORT | | | | | | | 5 | PX RECEIVE | | 10 | | 3 (0)| 00:00:01 | | 6 | PX SEND HASH (BLOCK ADDRESS) | :TQ10000 | 10 | | 3 (0)| 00:00:01 | | 7 | PX SELECTOR | | | | | | |* 8 | INDEX RANGE SCAN | SYS_AI_600vgjmtqsgv3 10 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 8 - access("CODE"=42) Statistics ---------------------------------------------------------- 12 recursive calls 0 db block gets 13 consistent gets 0 physical reads 0 redo size 867 bytes sent via SQL*Net to client 588 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 10 rows processed
We notice the new Automatic Index has been used by the CBO to substantially improve the performance of the query (just 13 consistent gets).
OK, so that’s the end of the Intro. In the next blog article, we’ll start looking at some of the specifics of how Auto Indexing works behind the covers and why it’s important to understand some of these workings…
Just curious what is “storage(“CODE”=42)” in the first execution plan. Was it exadata smart scan?
LikeLike
Hi Dmytro
Yes, most of my testing with Automatic Indexing was performed on the Dedicated Exadata Autonomous Transaction Processing cloud service.
Cheers
Richard
LikeLike
Hi, Can you change automatic indexing to always create a compressed index by default?
LikeLike
yes possible by setting exec dbms_auto_index.configure(‘auto_index_compression’,’on’); that will do Advanced index compression of ( compress advanced low) for the newly created auto indexes.
LikeLiked by 1 person
Hi Rajeshwaran
That’s correctly, although it didn’t initially make it into the official documentation when first released (it’s in there now with the 20c doco).
LikeLike