London March 2020: “Oracle Indexing Internals and Best Practices” and “Oracle Performance Diagnostics and Tuning” Seminars January 21, 2020
Posted by Richard Foote in Richard Foote Consulting, Richard Foote Seminars, Richard's Blog.add a comment
Time is fast running out to enroll for one of my acclaimed seminars I’ll be running in London, UK in March 2020. The dates and registration links are as follows:
23-24 March 2020: “Oracle Indexing Internals and Best Practices” Seminar – Tickets and Registration Link
25-26 March 2020: “Oracle Performance Diagnostics and Tuning” Seminar – Tickets and Registration Link
You can also purchase tickets to both seminars at a special 20% combo discount (all enrollments so far have gone with this option, so it’s obviously the way to go):
23-26 March 2020: Both “Oracle Indexing Internals and Best Practices” and “Oracle Performance Diagnostics and Tuning” Seminars – Tickets and Registration Link
The cost for each individual seminar is:
- Early Bird Rate (enrollments prior to 31 January 2020) £990.00 (+ VAT)
- General Rate (enrollments post 31 January 2020) £1190 (+VAT)
The cost for the seminar combo is:
- Early Bird Rate (enrollments prior to 31 January 2020) £1550.00 (+ VAT)
- General Rate (enrollments post 31 January 2020) £1900 (+VAT)
The venue is the rather nice Hilton London Kensington.
Prices include attendance to the seminar, both soft and hard copy of the extensive seminar materials, lunch and morning/afternoon tea/coffee.
Both seminars are very highly acclaimed, with past attendees universally applauding the quality and educational outcomes of the training. They’re both aimed at Oracle Professionals (DBAs and Developers) who are interested in Performance Tuning and how to maximise the performance of both Oracle Databases and associated applications.
All the details of the Oracle Indexing Internals and Best Practices Seminar.
All the details of the Oracle Performance Diagnostic and Tuning Seminar.
Both seminars have strictly limited places to ensure a quality event for all attendees with venues booked with only small classes in mind. So I recommend booking early (as it’s cheaper) and to avoid possible disappointment. I don’t get to run these kind of events in the UK very often (it would be over 2 years since I last run seminars in London) so do take advantage of attending what will be a unique training opportunity while you can.
If you have any questions, please leave a comment or contact me at richard@richardfooteconsulting.com.
Hope to see you at one or both of these seminars next year !!
Oracle Database 19c Automatic Indexing: Minimum Number Of Required Indexes (Low) January 20, 2020
Posted by Richard Foote in 19c, 19c New Features, Automatic Indexing, Autonomous Database, Autonomous Transaction Processing, Oracle Indexes.add a comment
As I discussed in my previous posts, Oracle Automatic Indexing will try and create as few indexes as possible to satisfy existing workloads, even if that means reordering the columns in an existing index.
To illustrate how Automatic Indexing creates as few indexes as possible, I’ll create the following table which has a number of columns with differing numbers of distinct values:
SQL> create table thin_white_duke (id number, code1 number, code2 number, code3 number, code4 number, name varchar2(42)); Table created. SQL> insert into thin_white_duke select rownum, ceil(dbms_random.value(0, 100)), ceil(dbms_random.value(0, 1000)), ceil(dbms_random.value(0, 10000)), ceil(dbms_random.value(0, 100000)), 'David Bowie' from dual connect by level <= 10000000; 10000000 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats(ownname=>null, tabname=>'THIN_WHITE_DUKE'); PL/SQL procedure successfully completed. SQL> select column_name, num_distinct, density from user_tab_columns where table_name='THIN_WHITE_DUKE'; COLUMN_NAME NUM_DISTINCT DENSITY --------------- ------------ ---------- ID 9914368 1.0086E-07 CODE1 100 .01 CODE2 1000 .001 CODE3 10000 .0001 CODE4 100824 9.9183E-06 NAME 1 1
I then run the following workload within a 15 minute window between Automatic Index tasks:
SQL> select * from thin_white_duke where id=42; SQL> select * from thin_white_duke where code1=42; SQL> select * from thin_white_duke where code2=42; SQL> select * from thin_white_duke where code3=42; SQL> select * from thin_white_duke where code4=42; SQL> select * from thin_white_duke where code1=42 and code2=42; SQL> select * from thin_white_duke where code1=42 and code3=42; SQL> select * from thin_white_duke where code1=42 and code4=42; SQL> select * from thin_white_duke where code2=42 and code1=42; SQL> select * from thin_white_duke where code2=42 and code3=42; SQL> select * from thin_white_duke where code2=42 and code4=42; SQL> select * from thin_white_duke where code3=42 and code1=42; SQL> select * from thin_white_duke where code3=42 and code2=42; SQL> select * from thin_white_duke where code3=42 and code4=42; SQL> select * from thin_white_duke where code4=42 and code1=42; SQL> select * from thin_white_duke where code4=42 and code2=42; SQL> select * from thin_white_duke where code4=42 and code3=42; SQL> select * from thin_white_duke where code1=42 and code2=42 and code3=42; SQL> select * from thin_white_duke where code1=42 and code2=42 and code4=42; SQL> select * from thin_white_duke where code1=42 and code3=42 and code4=42; SQL> select * from thin_white_duke where code2=42 and code1=42 and code3=42; SQL> select * from thin_white_duke where code2=42 and code1=42 and code4=42; SQL> select * from thin_white_duke where code2=42 and code3=42 and code4=42; SQL> select * from thin_white_duke where code3=42 and code1=42 and code2=42; SQL> select * from thin_white_duke where code3=42 and code1=42 and code4=42; SQL> select * from thin_white_duke where code3=42 and code2=42 and code4=42; SQL> select * from thin_white_duke where code4=42 and code1=42 and code2=42; SQL> select * from thin_white_duke where code4=42 and code1=42 and code3=42; SQL> select * from thin_white_duke where code4=42 and code2=42 and code3=42; SQL> select * from thin_white_duke where code1=42 and code2=42 and code3=42 and code4=42;
Each of these queries have no choice but to perform a Full Table Scan as there are currently no indexes defined to the table. Each query uses a different column list, so for the 30 or so SQL statements, one could potentially create 30 or so different indexes to cover each and every SQL predicate combination used above.
But how many different indexes will Automatic Indexing create?
Let’s have a look…
SQL> select dbms_auto_index.report_last_activity() report from dual; REPORT -------------------------------------------------------------------------------- GENERAL INFORMATION ------------------------------------------------------------------------------- Activity start : 15-JUL-2019 07:46:25 Activity end : 15-JUL-2019 07:48:56 Executions completed : 1 Executions interrupted : 0 Executions with fatal error : 0 ------------------------------------------------------------------------------- SUMMARY (AUTO INDEXES) ------------------------------------------------------------------------------- Index candidates : 7 Indexes created (visible / invisible) : 7 (7 / 0) Space used (visible / invisible) : 1.8 GB (1.8 GB / 0 B) Indexes dropped : 0 SQL statements verified : 29 SQL statements improved (improvement factor) : 29 (147.2x) SQL plan baselines created : 0 Overall improvement factor : 147.2x ------------------------------------------------------------------------------- SUMMARY (MANUAL INDEXES) ------------------------------------------------------------------------------- Unused indexes : 0 Space used : 0 B Unusable indexes : 0
We can see that Automatic Indexing only create 7 different indexes, that’s it !!
If we look at the indexes that have been created:
INDEX DETAILS ------------------------------------------------------------------------------- 1. The following indexes were created: ------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------- | Owner | Table | Index | Key | Type | Properties | -------------------------------------------------------------------------------------------------- | BOWIE | THIN_WHITE_DUKE | SYS_AI_0u1qx8vgtstkb | CODE4,CODE1,CODE2 | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_2j5g09nzrhqsw | CODE2,CODE3,CODE4 | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_4y26dtkybxq6k | CODE3,CODE4 | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_5pmdyk5pjay8a | CODE3,CODE1,CODE4 | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_6uqhvvzabg5n8 | ID | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_bwfbc6nah6uga | CODE2,CODE4 | B-TREE | NONE | | BOWIE | THIN_WHITE_DUKE | SYS_AI_fftcb8q17yy6g | CODE1,CODE2,CODE3,CODE4 | B-TREE | NONE | --------------------------------------------------------------------------------------------------
We can see how the 7 indexes can collectively cover all 30 odd different SQL predicates within the workload, because the leading columns of at least one index has the necessary columns of each SQL predicate.
If we look at but one SQL example within the Automatic Index report, the query with the predicate on just the CODE4 column:
Parsing Schema Name : BOWIE SQL ID : 20h1p88d1u80r SQL Text : select * from thin_white_duke where code4=42 Improvement Factor : 1200.5x Execution Statistics: ----------------------------- Original Plan Auto Index Plan ---------------------------- ---------------------------- Elapsed Time (s): 679689 1148 CPU Time (s): 724033 933 Buffer Gets: 162070 91 Optimizer Cost: 8617 103 Disk Reads: 0 2 Direct Writes: 0 0 Rows Processed: 264 88 Executions: 3 1 PLANS SECTION --------------------------------------------------------------------------------------------- - Original ----------------------------- Plan Hash Value : 2714752625 ------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost | Time | ------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | | | 8617 | | | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10000 | 99 | 3366 | 8617 | 00:00:01 | | 3 | PX BLOCK ITERATOR | | 99 | 3366 | 8617 | 00:00:01 | | 4 | TABLE ACCESS STORAGE FULL | THIN_WHITE_DUKE | 99 | 3366 | 8617 | 00:00:01 | ------------------------------------------------------------------------------------------ - With Auto Indexes ----------------------------- Plan Hash Value : 2447525579 ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 88 | 2992 | 103 | 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID BATCHED | THIN_WHITE_DUKE | 88 | 2992 | 103 | 00:00:01 | | * 2 | INDEX RANGE SCAN | SYS_AI_0u1qx8vgtstkb | 99 | | 3 | 00:00:01 | -------------------------------------------------------------------------------------------------------
We see it can now be serviced with the new SYS_AI_0u1qx8vgtstkb index, because it has the following columns (CODE4,CODE1,CODE2), with the CODE4 column as the leading column.
If we look at the details of all these new Automatic Indexes:
SQL> select index_name, auto, constraint_index, visibility, compression, status, num_rows, leaf_blocks, clustering_factor from user_indexes where table_name='THIN_WHITE_DUKE'; INDEX_NAME AUT CON VISIBILIT COMPRESSION STATUS NUM_ROWS LEAF_BLOCKS CLUSTERING_FACTOR -------------------- --- --- --------- ------------- -------- ---------- ----------- ----------------- SYS_AI_6uqhvvzabg5n8 YES NO VISIBLE DISABLED VALID 10000000 23553 53336 SYS_AI_fftcb8q17yy6g YES NO VISIBLE DISABLED VALID 10000000 37322 9999819 SYS_AI_2j5g09nzrhqsw YES NO VISIBLE DISABLED VALID 10000000 33154 9999815 SYS_AI_bwfbc6nah6uga YES NO VISIBLE DISABLED VALID 10000000 27564 9999822 SYS_AI_5pmdyk5pjay8a YES NO VISIBLE DISABLED VALID 10000000 31908 9999804 SYS_AI_4y26dtkybxq6k YES NO VISIBLE DISABLED VALID 10000000 27697 9999818 SYS_AI_0u1qx8vgtstkb YES NO VISIBLE DISABLED VALID 10000000 31783 9999819 SQL> select index_name, column_name, column_position from user_ind_columns where table_name='THIN_WHITE_DUKE' order by index_name, column_position; INDEX_NAME COLUMN_NAME COLUMN_POSITION -------------------- --------------- --------------- SYS_AI_0u1qx8vgtstkb CODE4 1 SYS_AI_0u1qx8vgtstkb CODE1 2 SYS_AI_0u1qx8vgtstkb CODE2 3 SYS_AI_2j5g09nzrhqsw CODE2 1 SYS_AI_2j5g09nzrhqsw CODE3 2 SYS_AI_2j5g09nzrhqsw CODE4 3 SYS_AI_4y26dtkybxq6k CODE3 1 SYS_AI_4y26dtkybxq6k CODE4 2 SYS_AI_5pmdyk5pjay8a CODE3 1 SYS_AI_5pmdyk5pjay8a CODE1 2 SYS_AI_5pmdyk5pjay8a CODE4 3 SYS_AI_6uqhvvzabg5n8 ID 1 SYS_AI_bwfbc6nah6uga CODE2 1 SYS_AI_bwfbc6nah6uga CODE4 2 SYS_AI_fftcb8q17yy6g CODE1 1 SYS_AI_fftcb8q17yy6g CODE2 2 SYS_AI_fftcb8q17yy6g CODE3 3 SYS_AI_fftcb8q17yy6g CODE4 4
The 7 newly created Automatic Indexes are all VISIBLE and VALID and can collectively service all 30 odd different SQL predicates of the captured workload.
I just know from experience that many DBAs and Developers out there would create many more than just these 7 indexes, partly because it’s just easier to create a new index for each new SQL predicate that doesn’t currently have an appropriate index and partly because it’s not always easy to capture and know what all SQL predicate combinations might be in use by an application.
This is one of the really nice capabilities of Automatic Indexing, in that it tries to service the known workloads it captures with as few indexes as possible, that have all be proven first to indeed improve SQL performance.
In my next blog post, I’ll show another trick that Automatic Indexing can do to reduce the number of different indexes it needs to create…
Oracle Database 19c Automatic Indexing – Need Another Index (Another Brick in The Wall Part 2) January 16, 2020
Posted by Richard Foote in 19c, 19c New Features, Automatic Indexing, Autonomous Database, Oracle Indexes.add a comment
I previously discussed how Automatic Indexing can effectively cleverly reorder an existing index if it means it can now use the new index to satisfy new SQL predicates. In this post, we’ll explore this example further with some new workloads.
So, we previously ran SQL queries with SQL predicates in the following combinations:
- CODE1=42 and CODE2=42 and CODE3=42
- CODE2=42 and CODE3=42
- CODE3=42
so an index based on CODE3, CODE2, CODE1 is able to satisfy all 3 existing predicates.
If we now run a new query with the following predicates based on CODE2=42 and CODE1=42:
SQL> select * from major_tom where code2=42 and code1=42; no rows selected Execution Plan ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 28 | 7318 (6)|00:00:01 | | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 28 | 7318 (6)|00:00:01 | | 3 | PX BLOCK ITERATOR | | 1 | 28 | 7318 (6)|00:00:01 | |* 4 | TABLE ACCESS STORAGE FULL| MAJOR_TOM | 1 | 28 | 7318 (6)|00:00:01 | ----------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - storage("CODE1"=42 AND "CODE2"=42) filter("CODE1"=42 AND "CODE2"=42) Statistics ---------------------------------------------------------- 8 recursive calls 4 db block gets 45853 consistent gets 0 physical reads 0 redo size 645 bytes sent via SQL*Net to client 577 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed
The current previously re-ordered index can’t now satisfy this new predicate as the leading column of the index (CODE3) is not specified in the SQL predicate and the CBO considers an Index Skip Scan as too expensive an operation. So a Full Table Scan is chosen here by the CBO.
If we wait and see what Automatic Indexing decides to now do:
SQL> select dbms_auto_index.report_last_activity() report from dual; REPORT -------------------------------------------------------------------------------- GENERAL INFORMATION ------------------------------------------------------------------------------- Activity start : 21-JUN-2019 07:41:55 Activity end : 21-JUN-2019 07:42:49 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) : 201.33 MB (201.33 MB / 0 B) Indexes dropped : 0 SQL statements verified : 1 SQL statements improved (improvement factor) : 1 (5.1x) SQL plan baselines created : 0 Overall improvement factor : 5.1x ------------------------------------------------------------------------------- SUMMARY (MANUAL INDEXES) ------------------------------------------------------------------------------- Unused indexes : 0 Space used : 0 B Unusable indexes : 0 -------------------------------------------------------------------------------
We notice that a new index has been created…
INDEX DETAILS ------------------------------------------------------------------------------- The following indexes were created: -------------------------------------------------------------------------------- | Owner | Table | Index | Key | Type | Properties | -------------------------------------------------------------------------------- | BOWIE | MAJOR_TOM | SYS_AI_gmhdbjx21zcr1 | CODE1,CODE2 | B-TREE | NONE | -------------------------------------------------------------------------------- VERIFICATION DETAILS ------------------------------------------------------------------------------- The performance of the following statements improved: ------------------------------------------------------------------------------- Parsing Schema Name : BOWIE SQL ID : 3y246nzwdpybv SQL Text : select * from major_tom where code2=42 and code1=4 Improvement Factor : 5.1x
So Automatic Indexing has decided to now create a new, second index (SYS_AI_gmhdbjx21zcr1) on the table based on CODE1, CODE2, as a single index is no longer capable to address all known SQL predicates.
SQL> select index_name, column_name, column_position from user_ind_columns where table_name='MAJOR_TOM' order by index_name, column_position; INDEX_NAME COLUMN_NAME COLUMN_POSITION ------------------------- -------------------- --------------- SYS_AI_00hxxxkgb821n CODE3 1 SYS_AI_00hxxxkgb821n CODE2 2 SYS_AI_00hxxxkgb821n CODE1 3 SYS_AI_gmhdbjx21zcr1 CODE1 1 SYS_AI_gmhdbjx21zcr1 CODE2 2
So we now have two indexes to cater for all known SQL predicates in which an index has been shown to improve performance.
Automatic Indexing will try and create the minimum number of indexes possible to cater for all known SQL workloads.
In my next post, we’ll look at a more complex example in which there could potentially be numerous different indexes that could cater for more extensive workloads and how Automatic Indexing copes rather splendidly…
“Oracle Performance Diagnostics and Tuning” Seminar: Berlin, Germany 31 March – 1 April 2020 January 14, 2020
Posted by Richard Foote in Oracle Performance Diagnostics and Tuning Seminar.add a comment
I’m very excited to be running my high acclaimed “Oracle Performance Diagnostics and Tuning” Seminar in Berlin, Germany on 31 March – 1 April 2020 in conjunction with DOUG. If you enjoyed my “Oracle Indexing Internals and Best Practices” Seminar, you will simply love this seminar 🙂
This seminar details how to maximise the performance of both Oracle databases and associated applications and how to diagnose and address any performance issues as quickly and effectively as possible.
When an application suddenly runs “slow” or when people start complaining about the “poor performance” of the database, there’s often some uncertainty in how to most quickly and most accurately determine the “root” cause of any such slowdown and effectively address any associated issues. In this seminar, we explore a Tuning Methodology that helps Oracle professionals to both quickly and reliably determine the actual causes of performance issues and so ensure the effectiveness of any applied resolutions.
Looking at a number of real-world scenarios and numerous actual examples and test cases, this seminar will show participants how to confidently and reliably diagnose performance issues. The seminar explores in much detail the various diagnostics tools and reports available in Oracle to assist in determining any database performance issue and importantly WHEN and HOW to effectively use each approach. Additionally, participants are also invited to share their own database AWR reports where we can apply the principles learnt in diagnosing the performance of their actual databases/applications.
One of the more common reasons for poor Oracle performance is inefficient or poorly running SQL. This seminar explores in much detail how SQL is executed within the Oracle database, the various issues and related concepts important in understanding why SQL might be inefficient and the many capabilities and features Oracle has in helping to both resolve SQL performance issues and to maintain the stability and reliability of SQL execution.
It’s a fun, but intense, content rich seminar that is suitable for people of all experiences (from beginners to seasoned Oracle experts).
For all the details regarding seminar content, venue, costs and how to register, please visit: https://www.doag.org/de/eventdetails?tx_doagevents_single[id]=589552
Places are already filling up so please book early to avoid disappointment !!