Gary Gordhamer
Oracle ACE Pro
Managing Principal Consultant
W @ggordham
W linkedin.com/in/ggordhamer/
W gary.gordhamer@viscosityna.com
Oracle Tuning Tips
My best developer tuning tips
Utah Oracle User Group
April 11, 2023
Now With Cats
JOIN US AT THE
ORACLE DATABASE FORUM
4 jam-packed days of In-depth days of technical insights, training & workshops.
Plus, hear directly from the Oracle Database team and other customers!
REGISTRATION NOW OPEN!
GET THE LATEST ON:
• Oracle Database innovations
• Elastic Computing
• Availability in a Cloud World
• Security & Manageability
• Security and Zero Trust
• Ransomware
• Enterprise Manager 13.5
• Machine Learning
32 Years of IT experience
31 years with Oracle technology
• Database 6.x – 23c
• Oracle Financials 7, E-Business Suite R11, R12.1, R12.2
IDM integrations and Security hardening
Industries including
• manufacturing
• financial
• marketing
• healthcare,
• utilities
• government
Member of the Quest IOUG Database & Technology
Community
serving on the advisory board
Gary Gordhamer
Oracle ACE Pro
Managing Principal Consultant
W @ggordham
W linkedin.com/in/ggordhamer/
W gary.gordhamer@viscosityna.com
Viscosity’s Oracle ACEs
The Oracle ACE Program
The Oracle ACE Program recognizes and rewards individuals for their
contributions to the Oracle community.
Charles Kim
CEO | Co-Founder
W @racdba
W ACE Director
Craig Shallahamer
Applied AI Scientist
W @orapub
W ACE Director
Rich Niemiec
Chief Innovation Officer
W @richniemiec
W ACE Director
Sean Scott
Principal Consultant
W @oraclesean
W ACE Pro
Gary Gordhamer
Principal Consultant
W @ggordham
W ACE Pro
Viscosity Pillars and Delivery Models
Workshops Assessments
Proof of
Concepts
Training
Turnkey
Projects
Managed
Services
Oracle & SQL Server PostGres
Performance Tuning
Data Replication
Data Warehousing Analytics
Data Integration
ERP Blue Prints
Database Upgrades
APEX
EBS
Web/Mobile Apps
.Net and C#
E-Business Suite
SAAS/PAAS
Azure Gold Partner
Cloud Migrations
Engineered Systems
Oracle Cloud Partner
Google Partner
AWS Partner Hybrid Cloud
We’ve written the Books!
All Viscosity hosted
webinar recordings and
conference session
slide decks will be
posted to
www.OraPub.com for
free and paid members!
OraPub.com is powered by Viscosity!
Oracle 19c Hands-On Experience
Publications coming soon
SOON
https://a.co/d/9ooeQVy
Want to try this out / follow along?
You can download all the scripts from GitHub
https://github.com/ggordham/ora-presentations/tree/main/tune-tips-UTOUG
Or: https://bit.ly/3Kl7s6E bit.ly / 3Kl7s6E
All information are ”as is” and meant for teaching purposes
only.
DO NOT run these in any production system or system
relied upon by your development teams.
So, you have a bad SQL statement?
Options to change the performance of a bad SQL:
• Look at environment setup (like statistics / missing index)
• Change the SQL / add a HINT
• Apply a SQL PROFILE
• Use a SQL PLAN BASELINE
• Use SQL Rewrite
• Create and apply a SQL PATCH
Step 1: identify how a SQL statement is performing
Step 2: what is a better performance option for that SQL statement
Step 3: apply a fix from the list above
Agenda
• What is SQL tuning
• Basic SQL info
• Optimizer basics
• SQL Tuning Tools
• Explain plan
• Statistics
• SQL Profile
• SQL Patch - the hack
• Playing with the
Optimizer
• Q&A
1. What is SQL tuning
2. What tools should I use
3. Explain Plan Lies
4. Statistics + Histograms = +1
5. Tuning Advisor + AWR top N SQL = +1
6. Why do SQL Profiles fail?
7. Create a SQL Baseline from cursor cache
8. How to make a SQL Patch
9. Playing with Optimizer
10. Why is my index not being used?
(clustering)
SQL Tuning
SQL Statement – what data you want Oracle to retrieve
Execution Plan – method Oracle will use to retrieve the data
SELECT sum(t1.c),
sum(t2.c)
FROM t1, t2
WHERE t1.a = t2.a
AND t1.d = :1
Oracle
Optimizer
Object Metadata Object Statistics
System Statistics
SQL Baseline
Plan
1 --
2 –-
3 –-
4 --
SQL Profile
(execution Statistics) Plan
1 --
2 –-
3 –-
4 --
Plan List
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Execute
Optimizer
Environment
SQL Tuning – the art of affecting one or more parts of this process to
decrees execution time or resource consumption
1. Submit SQL 2. Collect Information 3. Generate Possible Plans 4. Check Baselines 5. Pick Plan
Execute!
Cursor Cache – (G)V$SQL
BASIC SQL INFORMATION
• SQL_ID – unique ID based on SQL text
(will change if the text changes)
• SQL_TEXT – first 1,000 characters of SQL, consider looking at SQL_FULLTEXT (CLOB)
• PLAN_HASH_VALUE – representation of Execution Plan
• EXECUTIONS – number of executions since loaded into cache
• OPTIMIZER_COST – Execution Plan cost for cached Plan
SQL PARSING_SCHEMA SQL_ID PLAN_HASH_VALUE EXECS LAST_ACTIVE_TIME_FORM. OPTIMIZER_COST
-------------------------- --------------- ------------- --------------- ----- ---------------------- --------------
select count(*) from t2 w PERFLAB 19nmwtxrh5rf1 3321871023 115 13-Sep-2021 16:57:54 590
SELECT /*+ gather_plan_st PERFLAB fua0hb5hfst77 906334482 144 13-Sep-2021 16:57:54 1892
select count(t1.a) from t PERFLAB 38b5rzb4bfmdw 4224043856 39 13-Sep-2021 16:57:07 555
select sum(t1.a + t2.c) f PERFLAB 979hgkk210sqw 4205221947 50 13-Sep-2021 16:57:20 365
select sum(t1.a + t2.c) f PERFLAB 979hgkk210sqw 1965891112 1 13-Sep-2021 16:56:26 1537
SQL Tuning – Tools
* Additional License Required
Runs
Statement
SQL
Execution
Steps
Object
Information
Database
Environment
HTML
Reports
Easy to
read
Requires
Install
Explain Plan Maybe Yes No No Maybe Yes No
SQL Monitor* Maybe Yes No No Yes Yes No
SQL Health
Check (HC) No Yes Extensivie Yes Yes Yes No
SQL Trace Yes Yes Little Maybe No No No
CBO Trace Yes Yes Extensivie Some No No No
SQLT Maybe Yes Extensivie Extensivie Yes Yes Yes
ADDM* No Yes Some Some Yes Yes No*
SQL Tuning
Advisor* Yes Yes Some Some Yes Yes No*
Tunning Remedy EE / SE License Notes
SQL Profile* EE Only Tuning License Plan generation
SQL Baseline Both No Plan choice
SQL Patch Both No Plan generation or plan execution
SQL Tuning –
These Tools Show Me What?
Explain Plan – What steps will be taken to execute the SQL
SQL Health Check – What is the status / details of all the objects touched by
the SQL
SQL Trace – What happened when the SQL was executed
CBO Trace – How did the Optimizer decide to execute the SQL
SQLT – Everything + some “Observations”
SQL Tuning Advisor – try's a lot of options and shows if something is better
Optimizer SQL Steps
SQL
Syntax
Check
Optimization
Semantic
Check
Shared
Pool
Check
Parsing
Row Source
Generation
Execution
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Plan
1 --
2 –-
3 –-
4 --
Generate
Multiple
Execution Plan
Options Query Plan
(make Outline)
Shared Pool
Soft Parse
Hard Parse ->
Plan
1 --
2 –-
3 –-
4 --
Object
Statistics
System
Statistics
SQL
Profile
Baseline
/*+ --
–-
–-
*/
Outline
/*+ --
–-
–-
*/
*Explain will show soft parse detail if
available
Note: Soft Parsing is impacted by bind
variable values
Explain Plan* / Monitor
SQL Health Check
SQL Trace
SQLTXplain
CBO Trace
SQL Profile
Baseline
Patch
Parts of an explain plan
• SQL_ID - Unique ID for the SQL statement
(should be consistent across instances unless
the text of SQL changes)
• Plan Hash Value – Unique for each plan generated
• Plan - details of steps taken to execute the SQL
• Predicate Information – how is the data being filtered / accessed
• Column Projection – what columns are involved in the execution
steps (are in the work area)
• Outline Data – could be used to generate a patch, also a
somewhat internal view of the execution plan
Getting an Explain Plan
Run a query or do
EXPLAIN PLAN FOR <query>
Get explain plan:
SELECT *
FROM
table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALL'));
Note: we cast the output of the function to be of type
“TABLE”
Only the “last” query you explain or run will be there
All plan
Use:
format=> 'ALL’
SQLDeveloper: Note: these are numbers based
on statistics on the objects or
system wide statistics
DEMO
Plan with statistics
Add hint to SQL:
/*+ gather_plan_statistics */
Use:
format=>'ALLSTATS LAST +cost +bytes’
format=>'ALLSTATS LAST ALL' E- is Estimates
A- is Actuals
DEMO
Do I need to run the SQL to tune it?
How do you know the performance of a
SQL if it does not run?
(tree falls, does it make a sound?)
Explain Plans are estimates
How do you know what needs to be
tuned, if you don’t see what the SQL is
doing?
Tracing can be invaluable, which requires
running the SQL statement
Optimizer Estimate vs Reality
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:00.04 | 1978 | 1976 |
| 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.04 | 1978 | 1976 |
| 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.04 | 1978 | 1976 |
| 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.04 | 1977 | 1975 |
|* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 1 |00:00:00.04 | 1974 | 1972 |
|* 5 | INDEX RANGE SCAN | T2I | 1 | 1 | | 2 (0)| 1 |00:00:00.01 | 3 | 3 |
| 6 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 1 | 9 | 3 (0)| 1 |00:00:00.01 | 1 | 1 |
------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:01.00 | 11089 | 4536 |
| 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:01.00 | 11089 | 4536 |
| 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 250K|00:00:00.93 | 11089 | 4536 |
| 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 250K|00:00:00.36 | 9118 | 2566 |
|* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 250K|00:00:00.05 | 1976 | 1971 |
|* 5 | INDEX RANGE SCAN | T2I | 250K| 1 | | 2 (0)| 250K|00:00:00.34 | 7142 | 595 |
| 6 | TABLE ACCESS BY INDEX ROWID| T2 | 250K| 1 | 9 | 3 (0)| 250K|00:00:00.45 | 1971 | 1970 |
------------------------------------------------------------------------------------------------------------------------------
Execution Plans Are Not Absolutes!
An execution plan can have different costs
A SQL may run better with different execution plans at different
times
Plan stability tools can help and can hurt performance
• SQL Profiles are can be statistical information on generating plans
• SQL Baselines allow for multiple plans (👍)
• SQL Patches are the “hammer” of the toolset
Your system will change over time
• Data growth / change
• Hardware changes
• Software changes
Your tuning methodology needs to adapt to change!
Statistics – what are they good for?
Table: T2 Alias: T2: #Rows: 500000 SSZ: 0 LGR: 0 #Blks: 2011 AvgRowLen: 23.00
Column (#4): D(NUMBER)
AvgLen: 4 NDV: 253072 Nulls: 0 Density: 0.000004 Min: 1.0000 Max: 250000.0000
Estimated selectivity: 0.0000039514 , col: #4
Card: Original: 500000.000000 Rounded: 2 Computed: 1.975722 Non Adjusted: 1.975722
-------------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-------------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 556 | |
| 1 | SORT AGGREGATE | | 1 | 22 | | |
| 2 | NESTED LOOPS | | 2 | 44 | 556 | 00:00:07 |
| 3 | NESTED LOOPS | | 2 | 44 | 556 | 00:00:07 |
| 4 | TABLE ACCESS FULL | T1 | 2 | 26 | 550 | 00:00:07 |
| 5 | INDEX RANGE SCAN | T2I | 1 | | 2 | 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 9 | 3 | 00:00:01 |
-------------------------------------------------+-----------------------------------+
SELECT sum(t1.c), sum(t2.c)
FROM t1, t2
WHERE t1.a = t2.a AND t1.d = :idnum
Estimates
2 rows
or < 1%
Statistics + Histograms – better together!
Column (#4): D(NUMBER)
AvgLen: 4 NDV: 253072 Nulls: 0 Density: 0.000002 Min: 1.0000 Max: 250000.0000
Histogram: Hybrid #Bkts: 254 UncompBkts: 5433 EndPtVals: 254 ActualVal: yes
Estimated selectivity: 0.493858 , endpoint value predicate, col: #4
Card: Original: 500000.000000 Computed: 246929.000000 Non Adjusted: 246929.000000
---------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 1893 | |
| 1 | SORT AGGREGATE | | 1 | 22 | | |
| 2 | HASH JOIN | | 241K | 5305K | 1893 | 00:00:23 |
| 3 | TABLE ACCESS FULL | T1 | 241K | 3135K | 550 | 00:00:07 |
| 4 | TABLE ACCESS FULL | T2 | 488K | 4395K | 549 | 00:00:07 |
---------------------------------------+-----------------------------------+
SELECT sum(t1.c), sum(t2.c)
FROM t1, t2
WHERE t1.a = t2.a AND t1.d = :idnum
We went from:
2 rows to
246,929 rows
Or 49.3%
What’s lower?
741,000
or
1,893
Same Query, Different Bind Value
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:00.01 | 1980 |
| 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.01 | 1980 |
| 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.01 | 1980 |
| 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.01 | 1979 |
|* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 1 |00:00:00.01 | 1976 |
|* 5 | INDEX RANGE SCAN | T2I | 1 | 1 | | 2 (0)| 1 |00:00:00.01 | 3 |
| 6 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 1 | 9 | 3 (0)| 1 |00:00:00.01 | 1 |
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 741K(100)| 1 |00:00:00.43 | 11089 |
| 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.43 | 11089 |
| 2 | NESTED LOOPS | | 1 | 246K| 5305K| 741K (1)| 250K|00:00:00.44 | 11089 |
| 3 | NESTED LOOPS | | 1 | 246K| 5305K| 741K (1)| 250K|00:00:00.30 | 9118 |
|* 4 | TABLE ACCESS FULL | T1 | 1 | 246K| 3134K| 550 (1)| 250K|00:00:00.04 | 1976 |
|* 5 | INDEX RANGE SCAN | T2I | 250K| 1 | | 2 (0)| 250K|00:00:00.18 | 7142 |
| 6 | TABLE ACCESS BY INDEX ROWID| T2 | 250K| 1 | 9 | 3 (0)| 250K|00:00:00.09 | 1971 |
---------------------------------------------------------------------------------------------------------------------
What is a Histogram?
Oracle normally has basic table statistics:
• Number of rows in the table
• Average size of each row
• Number of distinct values per column
Example without histogram
• Table has 500,000 rows, 253,072 distinct values in column D
by default, each value has two rows
Oracle can keep up to 255 ”buckets”
Here row value = 10 has 250,001 rows
The rest of the values have one row
DEMO
I have my explain plan, I checked stats, now what?
Getting the optimizer to do what you want:
Tuning Advisors
Changing what plan gets generated
• Change the SQL
• SQL Hint
• SQL Profile
• SQL Patch
Changing what plan the Optimizer chooses to Execute (plan stability)
• SQL Baseline (Plan Management)
Tunning Advisor + AWR = 👍
Tunning Advisor uses SQL history for better performing plans
• SQL = Fast on Monday, slow on Tuesday
• What plan is stored in AWR history?
You can also set the number of TOP N SQL to capture
• RETENTION – number of minutes to keep (57600 = 40 days)
• INTERVAL – how frequent to take snaps (30 = 30 minutes)
• TOPNSQL – How many SQL to capture (quantity) default = 30 (TYPICAL)
begin
dbms_workload_repository.modify_snapshot_settings(
retention => 57600,
interval => 30,
topnsql => 100);
end;
/*+ Not the fast one */
What are my AWR settings?
Note: Intervals are displayed in minutes
SELECT
src_dbname,
extract( day from snap_interval) *24*60+
extract( hour from snap_interval) *60+
extract( minute from snap_interval ) "Snapshot Interval",
extract( day from retention) *24*60+
extract( hour from retention) *60+
extract( minute from retention ) "Retention Interval",
topnsql
FROM
dba_hist_wr_control;
SRC_DBNAME Snapshot Interval Retention Interval TOPNSQL
----------- ----------------- ------------------ ----------
t1db 60 11520 DEFAULT
DEMO
What are SQL Profiles? (requires Tuning pack + EE)
• A collection of auxiliary statistics (sometimes) on a query
• Profiles are not tied to a specific execution plan
• Requires no changes to source code
• Gives the Optimizer information to help generate execution plans
– Cardinality adjustments
– Actual rows returned for specific WHERE clauses
• 18c introduced Exadata aware profiles
• Profiles tend to stay relevant even as data changes, though they
can become stale if large changes occur
• Utilizes hints to affect the plan generation process
Manage profiles through the DBMS_SQLTUNE package
Creating a SQL Profile
Run a SQL tuning task
SET ECHO ON
VAR task_name varchar2(30)
EXEC :task_name := dbms_sqltune.create_tuning_task(sql_id => '70nv63r37j039');
EXEC dbms_sqltune.execute_tuning_task( :task_name );
SELECT :task_name FROM dual;
View the Report
SET linesize 180
SET longchunksize 180
SET pagesize 900
SET long 1000000
SELECT dbms_sqltune.report_tuning_task( :task_name ) FROM dual;
EXEC dbms_sqltune.accept_sql_profile( task_name => :task_name, task_owner => user, replace => TRUE);
Accept the recommendation
Note: we are accepting all recommendations, since there is only one SQL in the task
Viewing the Profile
column sql_id format a13
SELECT p.name, p.signature,
dbms_sql_translator.sql_id( p.sql_text ) AS sql_id,
dbms_sql_translator.sql_hash( p.sql_text ) AS sql_hash,
type, status, force_matching,
p.sql_text
FROM dba_sql_profiles p;
NAME SIGNATURE SQL_ID SQL_HASH TYPE STATUS FOR
----------------------------------- --------------------- ------------- ---------- ------- -------- ---
SYS_SQLPROF_01811fa8f7df0003 17523641855749125419 70nv63r37j039 3329785961 MANUAL ENABLED NO
SQL_TEXT
--------------------------------------------------------------------------------
select /* PROFTEST */ count(*) from sales WHERE sale_date >= trunc(sysdate)
Profile information is stored in DBA_SQL_PROFILES
Note: we calculated the SQL_ID in this example, as profiles are matched to SQL
statements by using the signature and not SQL_ID. Profiles can also be set to use
FORCE_MATCHING signatures.
DEMO
SQL Profile is an Embedded SQL Hint – Failure?
You can see the hint by querying DBMSHXSP_SQL_PROFILE_ATTR view
SELECT dspa.profile_name, extractValue(value(h),'.') AS hint
FROM DBMSHSXP_SQL_PROFILE_ATTR dspa,
TABLE(xmlsequence(
extract(xmltype(dspa.comp_data),'/outline_data/hint'))) h;
PROFILE_NAME HINT
------------------------------ -------------------------------------------------------------------------
SYS_SQLPROF_01811fa8f7df0003 OPT_ESTIMATE(@"SEL$1", TABLE, "SALES"@"SEL$1", SCALE_ROWS=3.00842289e-06)
OPT_ESTIMATE(@"SEL$1", INDEX_SCAN, "SALES"@"SEL$1", "SALESI",
SCALE_ROWS=0.001760302242)
OPTIMIZER_FEATURES_ENABLE(default)
Query from Trace
QUERY BLOCK TEXT
****************
select /* PROFTEST */ COUNT(*) from sales WHERE sale_date >= trunc(sysdate)
Stmt: ******* UNPARSED QUERY IS *******
SELECT /*+ OPT_ESTIMATE (@"SEL$1" INDEX_SCAN "SALES"@"SEL$1" "SALESI" SCALE_ROWS=0.001760 ) OPT_ESTIMATE
(@"SEL$1" TABLE "SALES"@"SEL$1" SCALE_ROWS=0.000003 ) */ COUNT(*) "COUNT(*)" FROM "PERFLAB"."SALES"
"SALES" WHERE "SALES"."SALE_DATE">=TRUNC(SYSDATE@!)
DEMO
Profiles vs. Baselines
The Optimizer uses object and system stats +
bind variables to generate execution plans
• SQL Profile influences the optimizer plan creation
• SQL Baseline forces the optimizer to choose only accepted plans
Profiles and Baselines can be used together
Profiles can influence multiple SQL statements (force matching)
Profiles require tuning pack license (EE Only)
Baselines force a specific plan and only affect single statements
Baselines can contain multiple plans, and plans can evolve
Baselines are included in all versions (SE / EE)
Create a baseline from Cursor Cache
Scenario: you have a SQL with multiple execution plans in cache (v$sql)
• One of the plans runs faster / better than the others
• You would like to create a baseline for that plan and “fix” it
VARIABLE v_plan_cnt NUMBER
BEGIN
:v_plan_cnt := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
sql_id => 'adjwa8r407rzc’,
plan_hash_value => 3534348942
fixed => 'YES');
END;
/
SELECT :v_plan_cnt || ' Plans loaded' from dual;
DEMO
Note: you can modify a baseline with DBMS_SPM.ALTER_SQL_PLAN_BASELINE
What is a SQL Patch?
Part of the SQL Repair Advisor
• Allows to adjust a plan to work around a failure
• Embeds a hint into the SQL statement
• No additional license required
You can manually create a patch
• SYS.DBMS_SQLDIAG.CREATE_SQL_PATCH
• Applies to a single SQL statement using SQL ID or SQL Text
• When using SQL Text, applied after “normalization”
(whitespace and the case of non-literals are normalized)
DECLARE
l_patch_name VARCHAR2(4000);
BEGIN
l_patch_name := sys.dbms_sqldiag.create_sql_patch(
sql_id => 'adps0u414xj2s',
hint_text => 'FULL(@"SEL$1" "TAB1"@"SEL$1")',
name =>'q3_patch');
EEND;
/
Patch example
DEMO
Force the SQL to do a full table scan
Note: hint text came from outline portion of explain plan
Note: you can also provide sql_text instead of sql_id, this will change how the
matching occurs.
Playing With the Optimizer - 1
My SQL statement is not picking up an index.
1. Flush statement from cursor cache
2. At session level set:
3. Run Explain Plan
Forcing indexes to be 99% less expensive than would normally be
ALTER SESSION SET optimizer_index_cost_adj = 1;
Playing With the Optimizer - 2
My SQL statement is not picking up an index.
1. Flush statement from cursor cache
2. At session level set:
possible options are CHOOSE, CPU, IO
3. Run Explain Plan
Forcing Optimizer to cost on a different resource
ALTER SESSION SET "_optimizer_cost_model"=IO;
Playing With the Optimizer - 3
My SQL statement is not picking up an index.
1. Flush statement from cursor cache
2. At session level set:
3. Run Explain Plan
Are adaptive statistics helpful?
Possibly run a trace in this process instead of just explain plan?
ALTER SESSION SET optimizer_adaptive_statistics=TRUE;
Why is the Optimizer not using my index?
Index simple usage
• Unique scan – find NOT NULL data that is unique in an index
• Range scan – uses leading column of the index
• Skip scan – first column of multi-column index not used
Only used when all return columns in your query are in the index
• Full scan – using the index to sort data
• Fast full scan un-sorted uses index as source of table data
• Join scan use two or more index instead of table for data source
Reasons an index is not used
• You are searching for NULL (WHERE dept_no IS NULL)
– indexes do not store NULL values
• The number of rows you want to retrieve is not efficient
when using an index
Minimum of three blocks reads to get to one record,
reading > 20% of the data, the index can become inefficient
• Index clustering factor (related to range scans)
• Clustering factor is per index
• Related to how rows are stored in relation to the index columns
IDX Root
Block
IDX Leaf
Block
TBL Data
Block
Index Clustering
Cluster describes the relationship to the data indexed and blocks stored
Used when calculating if a RANGE SCAN would be helpful (BETWEEN)
• close to the number of table blocks = data order matches the index key
• close to the number of table rows = data scattered randomly across the blocks
TBL Block
-----------
Puri | Puri
TBL Block
-----------
Quinlan | Quinlan
TBL Block
-----------
Puri | Welles
TBL Block
-----------
Sheen | Puri
TBL Block
-----------
Lyon | Quinlan
TBL Block
-----------
Quinlan | Martin
V.S.
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
---------- --------------- --------- --------- -----------------
CUSTOMERS CUST_LNAME_IX 319 13 294
CUSTOMERS3 CUST3_LANME_IX 319 12 9
DEMO
Wrapping Up
Have a plan to find poor performing SQL
Have your tuning tools ready to use!
Know when each tool might be useful
Oracle will tune a lot of things for you, but
sometimes it wont
Practice in non-production!
1. What is SQL tuning
2. What tools should I use
3. Explain Plan Lies
4. Statistics + Histograms = +1
5. Tuning Advisor + AWR top N SQL = +1
6. Why do SQL Profiles fail?
7. Create a SQL Baseline from cursor cache
8. How to make a SQL Patch
9. Playing with Optimizer
10. Why is my index not being used? (clustering)
Open Q&A
Keep Up To Speed With all
Upcoming Events!
https://events.viscosityna.com
Follow Us Online!
Facebook.com/ViscosityNa
LinkedIn.com/company/Viscosity-North-America
@ViscosityNA
Viscosity North America
Viscosity_NA
• Oracle Database 19c SIG
• Upcoming calls: Feb. 10, Mar. 10, Apr. 14
• IOUG Cloud Computing SIG
• Upcoming calls: Feb. 16, Mar. 16, Apr. 20
• Oracle MAA Special Interest Group
• Upcoming calls: Mar. 15
Anyone is welcome to join the SIG call. SIG membership is not
required.
2
User Groups
31063115_1679409488310Developer_Tuning_Tips_-_UTOUG_Mar_2023.pdf

31063115_1679409488310Developer_Tuning_Tips_-_UTOUG_Mar_2023.pdf

  • 1.
    Gary Gordhamer Oracle ACEPro Managing Principal Consultant W @ggordham W linkedin.com/in/ggordhamer/ W gary.gordhamer@viscosityna.com Oracle Tuning Tips My best developer tuning tips Utah Oracle User Group April 11, 2023 Now With Cats
  • 2.
    JOIN US ATTHE ORACLE DATABASE FORUM 4 jam-packed days of In-depth days of technical insights, training & workshops. Plus, hear directly from the Oracle Database team and other customers! REGISTRATION NOW OPEN! GET THE LATEST ON: • Oracle Database innovations • Elastic Computing • Availability in a Cloud World • Security & Manageability • Security and Zero Trust • Ransomware • Enterprise Manager 13.5 • Machine Learning
  • 3.
    32 Years ofIT experience 31 years with Oracle technology • Database 6.x – 23c • Oracle Financials 7, E-Business Suite R11, R12.1, R12.2 IDM integrations and Security hardening Industries including • manufacturing • financial • marketing • healthcare, • utilities • government Member of the Quest IOUG Database & Technology Community serving on the advisory board Gary Gordhamer Oracle ACE Pro Managing Principal Consultant W @ggordham W linkedin.com/in/ggordhamer/ W gary.gordhamer@viscosityna.com
  • 4.
    Viscosity’s Oracle ACEs TheOracle ACE Program The Oracle ACE Program recognizes and rewards individuals for their contributions to the Oracle community. Charles Kim CEO | Co-Founder W @racdba W ACE Director Craig Shallahamer Applied AI Scientist W @orapub W ACE Director Rich Niemiec Chief Innovation Officer W @richniemiec W ACE Director Sean Scott Principal Consultant W @oraclesean W ACE Pro Gary Gordhamer Principal Consultant W @ggordham W ACE Pro
  • 5.
    Viscosity Pillars andDelivery Models Workshops Assessments Proof of Concepts Training Turnkey Projects Managed Services Oracle & SQL Server PostGres Performance Tuning Data Replication Data Warehousing Analytics Data Integration ERP Blue Prints Database Upgrades APEX EBS Web/Mobile Apps .Net and C# E-Business Suite SAAS/PAAS Azure Gold Partner Cloud Migrations Engineered Systems Oracle Cloud Partner Google Partner AWS Partner Hybrid Cloud
  • 6.
  • 7.
    All Viscosity hosted webinarrecordings and conference session slide decks will be posted to www.OraPub.com for free and paid members! OraPub.com is powered by Viscosity!
  • 8.
    Oracle 19c Hands-OnExperience Publications coming soon SOON https://a.co/d/9ooeQVy
  • 9.
    Want to trythis out / follow along? You can download all the scripts from GitHub https://github.com/ggordham/ora-presentations/tree/main/tune-tips-UTOUG Or: https://bit.ly/3Kl7s6E bit.ly / 3Kl7s6E All information are ”as is” and meant for teaching purposes only. DO NOT run these in any production system or system relied upon by your development teams.
  • 10.
    So, you havea bad SQL statement? Options to change the performance of a bad SQL: • Look at environment setup (like statistics / missing index) • Change the SQL / add a HINT • Apply a SQL PROFILE • Use a SQL PLAN BASELINE • Use SQL Rewrite • Create and apply a SQL PATCH Step 1: identify how a SQL statement is performing Step 2: what is a better performance option for that SQL statement Step 3: apply a fix from the list above
  • 11.
    Agenda • What isSQL tuning • Basic SQL info • Optimizer basics • SQL Tuning Tools • Explain plan • Statistics • SQL Profile • SQL Patch - the hack • Playing with the Optimizer • Q&A 1. What is SQL tuning 2. What tools should I use 3. Explain Plan Lies 4. Statistics + Histograms = +1 5. Tuning Advisor + AWR top N SQL = +1 6. Why do SQL Profiles fail? 7. Create a SQL Baseline from cursor cache 8. How to make a SQL Patch 9. Playing with Optimizer 10. Why is my index not being used? (clustering)
  • 12.
    SQL Tuning SQL Statement– what data you want Oracle to retrieve Execution Plan – method Oracle will use to retrieve the data SELECT sum(t1.c), sum(t2.c) FROM t1, t2 WHERE t1.a = t2.a AND t1.d = :1 Oracle Optimizer Object Metadata Object Statistics System Statistics SQL Baseline Plan 1 -- 2 –- 3 –- 4 -- SQL Profile (execution Statistics) Plan 1 -- 2 –- 3 –- 4 -- Plan List Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Execute Optimizer Environment SQL Tuning – the art of affecting one or more parts of this process to decrees execution time or resource consumption 1. Submit SQL 2. Collect Information 3. Generate Possible Plans 4. Check Baselines 5. Pick Plan Execute!
  • 13.
    Cursor Cache –(G)V$SQL BASIC SQL INFORMATION • SQL_ID – unique ID based on SQL text (will change if the text changes) • SQL_TEXT – first 1,000 characters of SQL, consider looking at SQL_FULLTEXT (CLOB) • PLAN_HASH_VALUE – representation of Execution Plan • EXECUTIONS – number of executions since loaded into cache • OPTIMIZER_COST – Execution Plan cost for cached Plan SQL PARSING_SCHEMA SQL_ID PLAN_HASH_VALUE EXECS LAST_ACTIVE_TIME_FORM. OPTIMIZER_COST -------------------------- --------------- ------------- --------------- ----- ---------------------- -------------- select count(*) from t2 w PERFLAB 19nmwtxrh5rf1 3321871023 115 13-Sep-2021 16:57:54 590 SELECT /*+ gather_plan_st PERFLAB fua0hb5hfst77 906334482 144 13-Sep-2021 16:57:54 1892 select count(t1.a) from t PERFLAB 38b5rzb4bfmdw 4224043856 39 13-Sep-2021 16:57:07 555 select sum(t1.a + t2.c) f PERFLAB 979hgkk210sqw 4205221947 50 13-Sep-2021 16:57:20 365 select sum(t1.a + t2.c) f PERFLAB 979hgkk210sqw 1965891112 1 13-Sep-2021 16:56:26 1537
  • 14.
    SQL Tuning –Tools * Additional License Required Runs Statement SQL Execution Steps Object Information Database Environment HTML Reports Easy to read Requires Install Explain Plan Maybe Yes No No Maybe Yes No SQL Monitor* Maybe Yes No No Yes Yes No SQL Health Check (HC) No Yes Extensivie Yes Yes Yes No SQL Trace Yes Yes Little Maybe No No No CBO Trace Yes Yes Extensivie Some No No No SQLT Maybe Yes Extensivie Extensivie Yes Yes Yes ADDM* No Yes Some Some Yes Yes No* SQL Tuning Advisor* Yes Yes Some Some Yes Yes No* Tunning Remedy EE / SE License Notes SQL Profile* EE Only Tuning License Plan generation SQL Baseline Both No Plan choice SQL Patch Both No Plan generation or plan execution
  • 15.
    SQL Tuning – TheseTools Show Me What? Explain Plan – What steps will be taken to execute the SQL SQL Health Check – What is the status / details of all the objects touched by the SQL SQL Trace – What happened when the SQL was executed CBO Trace – How did the Optimizer decide to execute the SQL SQLT – Everything + some “Observations” SQL Tuning Advisor – try's a lot of options and shows if something is better
  • 16.
    Optimizer SQL Steps SQL Syntax Check Optimization Semantic Check Shared Pool Check Parsing RowSource Generation Execution Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Plan 1 -- 2 –- 3 –- 4 -- Generate Multiple Execution Plan Options Query Plan (make Outline) Shared Pool Soft Parse Hard Parse -> Plan 1 -- 2 –- 3 –- 4 -- Object Statistics System Statistics SQL Profile Baseline /*+ -- –- –- */ Outline /*+ -- –- –- */ *Explain will show soft parse detail if available Note: Soft Parsing is impacted by bind variable values Explain Plan* / Monitor SQL Health Check SQL Trace SQLTXplain CBO Trace SQL Profile Baseline Patch
  • 17.
    Parts of anexplain plan • SQL_ID - Unique ID for the SQL statement (should be consistent across instances unless the text of SQL changes) • Plan Hash Value – Unique for each plan generated • Plan - details of steps taken to execute the SQL • Predicate Information – how is the data being filtered / accessed • Column Projection – what columns are involved in the execution steps (are in the work area) • Outline Data – could be used to generate a patch, also a somewhat internal view of the execution plan
  • 18.
    Getting an ExplainPlan Run a query or do EXPLAIN PLAN FOR <query> Get explain plan: SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALL')); Note: we cast the output of the function to be of type “TABLE” Only the “last” query you explain or run will be there
  • 19.
    All plan Use: format=> 'ALL’ SQLDeveloper:Note: these are numbers based on statistics on the objects or system wide statistics DEMO
  • 20.
    Plan with statistics Addhint to SQL: /*+ gather_plan_statistics */ Use: format=>'ALLSTATS LAST +cost +bytes’ format=>'ALLSTATS LAST ALL' E- is Estimates A- is Actuals DEMO
  • 21.
    Do I needto run the SQL to tune it? How do you know the performance of a SQL if it does not run? (tree falls, does it make a sound?) Explain Plans are estimates How do you know what needs to be tuned, if you don’t see what the SQL is doing? Tracing can be invaluable, which requires running the SQL statement
  • 22.
    Optimizer Estimate vsReality ------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | Reads | ------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:00.04 | 1978 | 1976 | | 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.04 | 1978 | 1976 | | 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.04 | 1978 | 1976 | | 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.04 | 1977 | 1975 | |* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 1 |00:00:00.04 | 1974 | 1972 | |* 5 | INDEX RANGE SCAN | T2I | 1 | 1 | | 2 (0)| 1 |00:00:00.01 | 3 | 3 | | 6 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 1 | 9 | 3 (0)| 1 |00:00:00.01 | 1 | 1 | ------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | Reads | ------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:01.00 | 11089 | 4536 | | 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:01.00 | 11089 | 4536 | | 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 250K|00:00:00.93 | 11089 | 4536 | | 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 250K|00:00:00.36 | 9118 | 2566 | |* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 250K|00:00:00.05 | 1976 | 1971 | |* 5 | INDEX RANGE SCAN | T2I | 250K| 1 | | 2 (0)| 250K|00:00:00.34 | 7142 | 595 | | 6 | TABLE ACCESS BY INDEX ROWID| T2 | 250K| 1 | 9 | 3 (0)| 250K|00:00:00.45 | 1971 | 1970 | ------------------------------------------------------------------------------------------------------------------------------
  • 23.
    Execution Plans AreNot Absolutes! An execution plan can have different costs A SQL may run better with different execution plans at different times Plan stability tools can help and can hurt performance • SQL Profiles are can be statistical information on generating plans • SQL Baselines allow for multiple plans (👍) • SQL Patches are the “hammer” of the toolset Your system will change over time • Data growth / change • Hardware changes • Software changes Your tuning methodology needs to adapt to change!
  • 24.
    Statistics – whatare they good for? Table: T2 Alias: T2: #Rows: 500000 SSZ: 0 LGR: 0 #Blks: 2011 AvgRowLen: 23.00 Column (#4): D(NUMBER) AvgLen: 4 NDV: 253072 Nulls: 0 Density: 0.000004 Min: 1.0000 Max: 250000.0000 Estimated selectivity: 0.0000039514 , col: #4 Card: Original: 500000.000000 Rounded: 2 Computed: 1.975722 Non Adjusted: 1.975722 -------------------------------------------------+-----------------------------------+ | Id | Operation | Name | Rows | Bytes | Cost | Time | -------------------------------------------------+-----------------------------------+ | 0 | SELECT STATEMENT | | | | 556 | | | 1 | SORT AGGREGATE | | 1 | 22 | | | | 2 | NESTED LOOPS | | 2 | 44 | 556 | 00:00:07 | | 3 | NESTED LOOPS | | 2 | 44 | 556 | 00:00:07 | | 4 | TABLE ACCESS FULL | T1 | 2 | 26 | 550 | 00:00:07 | | 5 | INDEX RANGE SCAN | T2I | 1 | | 2 | 00:00:01 | | 6 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 9 | 3 | 00:00:01 | -------------------------------------------------+-----------------------------------+ SELECT sum(t1.c), sum(t2.c) FROM t1, t2 WHERE t1.a = t2.a AND t1.d = :idnum Estimates 2 rows or < 1%
  • 25.
    Statistics + Histograms– better together! Column (#4): D(NUMBER) AvgLen: 4 NDV: 253072 Nulls: 0 Density: 0.000002 Min: 1.0000 Max: 250000.0000 Histogram: Hybrid #Bkts: 254 UncompBkts: 5433 EndPtVals: 254 ActualVal: yes Estimated selectivity: 0.493858 , endpoint value predicate, col: #4 Card: Original: 500000.000000 Computed: 246929.000000 Non Adjusted: 246929.000000 ---------------------------------------+-----------------------------------+ | Id | Operation | Name | Rows | Bytes | Cost | Time | ---------------------------------------+-----------------------------------+ | 0 | SELECT STATEMENT | | | | 1893 | | | 1 | SORT AGGREGATE | | 1 | 22 | | | | 2 | HASH JOIN | | 241K | 5305K | 1893 | 00:00:23 | | 3 | TABLE ACCESS FULL | T1 | 241K | 3135K | 550 | 00:00:07 | | 4 | TABLE ACCESS FULL | T2 | 488K | 4395K | 549 | 00:00:07 | ---------------------------------------+-----------------------------------+ SELECT sum(t1.c), sum(t2.c) FROM t1, t2 WHERE t1.a = t2.a AND t1.d = :idnum We went from: 2 rows to 246,929 rows Or 49.3% What’s lower? 741,000 or 1,893
  • 26.
    Same Query, DifferentBind Value --------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | --------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 553 (100)| 1 |00:00:00.01 | 1980 | | 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.01 | 1980 | | 2 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.01 | 1980 | | 3 | NESTED LOOPS | | 1 | 1 | 22 | 553 (1)| 1 |00:00:00.01 | 1979 | |* 4 | TABLE ACCESS FULL | T1 | 1 | 1 | 13 | 550 (1)| 1 |00:00:00.01 | 1976 | |* 5 | INDEX RANGE SCAN | T2I | 1 | 1 | | 2 (0)| 1 |00:00:00.01 | 3 | | 6 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 1 | 9 | 3 (0)| 1 |00:00:00.01 | 1 | --------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers | --------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 741K(100)| 1 |00:00:00.43 | 11089 | | 1 | SORT AGGREGATE | | 1 | 1 | 22 | | 1 |00:00:00.43 | 11089 | | 2 | NESTED LOOPS | | 1 | 246K| 5305K| 741K (1)| 250K|00:00:00.44 | 11089 | | 3 | NESTED LOOPS | | 1 | 246K| 5305K| 741K (1)| 250K|00:00:00.30 | 9118 | |* 4 | TABLE ACCESS FULL | T1 | 1 | 246K| 3134K| 550 (1)| 250K|00:00:00.04 | 1976 | |* 5 | INDEX RANGE SCAN | T2I | 250K| 1 | | 2 (0)| 250K|00:00:00.18 | 7142 | | 6 | TABLE ACCESS BY INDEX ROWID| T2 | 250K| 1 | 9 | 3 (0)| 250K|00:00:00.09 | 1971 | ---------------------------------------------------------------------------------------------------------------------
  • 27.
    What is aHistogram? Oracle normally has basic table statistics: • Number of rows in the table • Average size of each row • Number of distinct values per column Example without histogram • Table has 500,000 rows, 253,072 distinct values in column D by default, each value has two rows Oracle can keep up to 255 ”buckets” Here row value = 10 has 250,001 rows The rest of the values have one row DEMO
  • 28.
    I have myexplain plan, I checked stats, now what? Getting the optimizer to do what you want: Tuning Advisors Changing what plan gets generated • Change the SQL • SQL Hint • SQL Profile • SQL Patch Changing what plan the Optimizer chooses to Execute (plan stability) • SQL Baseline (Plan Management)
  • 29.
    Tunning Advisor +AWR = 👍 Tunning Advisor uses SQL history for better performing plans • SQL = Fast on Monday, slow on Tuesday • What plan is stored in AWR history? You can also set the number of TOP N SQL to capture • RETENTION – number of minutes to keep (57600 = 40 days) • INTERVAL – how frequent to take snaps (30 = 30 minutes) • TOPNSQL – How many SQL to capture (quantity) default = 30 (TYPICAL) begin dbms_workload_repository.modify_snapshot_settings( retention => 57600, interval => 30, topnsql => 100); end; /*+ Not the fast one */
  • 30.
    What are myAWR settings? Note: Intervals are displayed in minutes SELECT src_dbname, extract( day from snap_interval) *24*60+ extract( hour from snap_interval) *60+ extract( minute from snap_interval ) "Snapshot Interval", extract( day from retention) *24*60+ extract( hour from retention) *60+ extract( minute from retention ) "Retention Interval", topnsql FROM dba_hist_wr_control; SRC_DBNAME Snapshot Interval Retention Interval TOPNSQL ----------- ----------------- ------------------ ---------- t1db 60 11520 DEFAULT DEMO
  • 31.
    What are SQLProfiles? (requires Tuning pack + EE) • A collection of auxiliary statistics (sometimes) on a query • Profiles are not tied to a specific execution plan • Requires no changes to source code • Gives the Optimizer information to help generate execution plans – Cardinality adjustments – Actual rows returned for specific WHERE clauses • 18c introduced Exadata aware profiles • Profiles tend to stay relevant even as data changes, though they can become stale if large changes occur • Utilizes hints to affect the plan generation process Manage profiles through the DBMS_SQLTUNE package
  • 32.
    Creating a SQLProfile Run a SQL tuning task SET ECHO ON VAR task_name varchar2(30) EXEC :task_name := dbms_sqltune.create_tuning_task(sql_id => '70nv63r37j039'); EXEC dbms_sqltune.execute_tuning_task( :task_name ); SELECT :task_name FROM dual; View the Report SET linesize 180 SET longchunksize 180 SET pagesize 900 SET long 1000000 SELECT dbms_sqltune.report_tuning_task( :task_name ) FROM dual; EXEC dbms_sqltune.accept_sql_profile( task_name => :task_name, task_owner => user, replace => TRUE); Accept the recommendation Note: we are accepting all recommendations, since there is only one SQL in the task
  • 33.
    Viewing the Profile columnsql_id format a13 SELECT p.name, p.signature, dbms_sql_translator.sql_id( p.sql_text ) AS sql_id, dbms_sql_translator.sql_hash( p.sql_text ) AS sql_hash, type, status, force_matching, p.sql_text FROM dba_sql_profiles p; NAME SIGNATURE SQL_ID SQL_HASH TYPE STATUS FOR ----------------------------------- --------------------- ------------- ---------- ------- -------- --- SYS_SQLPROF_01811fa8f7df0003 17523641855749125419 70nv63r37j039 3329785961 MANUAL ENABLED NO SQL_TEXT -------------------------------------------------------------------------------- select /* PROFTEST */ count(*) from sales WHERE sale_date >= trunc(sysdate) Profile information is stored in DBA_SQL_PROFILES Note: we calculated the SQL_ID in this example, as profiles are matched to SQL statements by using the signature and not SQL_ID. Profiles can also be set to use FORCE_MATCHING signatures. DEMO
  • 34.
    SQL Profile isan Embedded SQL Hint – Failure? You can see the hint by querying DBMSHXSP_SQL_PROFILE_ATTR view SELECT dspa.profile_name, extractValue(value(h),'.') AS hint FROM DBMSHSXP_SQL_PROFILE_ATTR dspa, TABLE(xmlsequence( extract(xmltype(dspa.comp_data),'/outline_data/hint'))) h; PROFILE_NAME HINT ------------------------------ ------------------------------------------------------------------------- SYS_SQLPROF_01811fa8f7df0003 OPT_ESTIMATE(@"SEL$1", TABLE, "SALES"@"SEL$1", SCALE_ROWS=3.00842289e-06) OPT_ESTIMATE(@"SEL$1", INDEX_SCAN, "SALES"@"SEL$1", "SALESI", SCALE_ROWS=0.001760302242) OPTIMIZER_FEATURES_ENABLE(default) Query from Trace QUERY BLOCK TEXT **************** select /* PROFTEST */ COUNT(*) from sales WHERE sale_date >= trunc(sysdate) Stmt: ******* UNPARSED QUERY IS ******* SELECT /*+ OPT_ESTIMATE (@"SEL$1" INDEX_SCAN "SALES"@"SEL$1" "SALESI" SCALE_ROWS=0.001760 ) OPT_ESTIMATE (@"SEL$1" TABLE "SALES"@"SEL$1" SCALE_ROWS=0.000003 ) */ COUNT(*) "COUNT(*)" FROM "PERFLAB"."SALES" "SALES" WHERE "SALES"."SALE_DATE">=TRUNC(SYSDATE@!) DEMO
  • 35.
    Profiles vs. Baselines TheOptimizer uses object and system stats + bind variables to generate execution plans • SQL Profile influences the optimizer plan creation • SQL Baseline forces the optimizer to choose only accepted plans Profiles and Baselines can be used together Profiles can influence multiple SQL statements (force matching) Profiles require tuning pack license (EE Only) Baselines force a specific plan and only affect single statements Baselines can contain multiple plans, and plans can evolve Baselines are included in all versions (SE / EE)
  • 36.
    Create a baselinefrom Cursor Cache Scenario: you have a SQL with multiple execution plans in cache (v$sql) • One of the plans runs faster / better than the others • You would like to create a baseline for that plan and “fix” it VARIABLE v_plan_cnt NUMBER BEGIN :v_plan_cnt := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE( sql_id => 'adjwa8r407rzc’, plan_hash_value => 3534348942 fixed => 'YES'); END; / SELECT :v_plan_cnt || ' Plans loaded' from dual; DEMO Note: you can modify a baseline with DBMS_SPM.ALTER_SQL_PLAN_BASELINE
  • 37.
    What is aSQL Patch? Part of the SQL Repair Advisor • Allows to adjust a plan to work around a failure • Embeds a hint into the SQL statement • No additional license required You can manually create a patch • SYS.DBMS_SQLDIAG.CREATE_SQL_PATCH • Applies to a single SQL statement using SQL ID or SQL Text • When using SQL Text, applied after “normalization” (whitespace and the case of non-literals are normalized)
  • 38.
    DECLARE l_patch_name VARCHAR2(4000); BEGIN l_patch_name :=sys.dbms_sqldiag.create_sql_patch( sql_id => 'adps0u414xj2s', hint_text => 'FULL(@"SEL$1" "TAB1"@"SEL$1")', name =>'q3_patch'); EEND; / Patch example DEMO Force the SQL to do a full table scan Note: hint text came from outline portion of explain plan Note: you can also provide sql_text instead of sql_id, this will change how the matching occurs.
  • 39.
    Playing With theOptimizer - 1 My SQL statement is not picking up an index. 1. Flush statement from cursor cache 2. At session level set: 3. Run Explain Plan Forcing indexes to be 99% less expensive than would normally be ALTER SESSION SET optimizer_index_cost_adj = 1;
  • 40.
    Playing With theOptimizer - 2 My SQL statement is not picking up an index. 1. Flush statement from cursor cache 2. At session level set: possible options are CHOOSE, CPU, IO 3. Run Explain Plan Forcing Optimizer to cost on a different resource ALTER SESSION SET "_optimizer_cost_model"=IO;
  • 41.
    Playing With theOptimizer - 3 My SQL statement is not picking up an index. 1. Flush statement from cursor cache 2. At session level set: 3. Run Explain Plan Are adaptive statistics helpful? Possibly run a trace in this process instead of just explain plan? ALTER SESSION SET optimizer_adaptive_statistics=TRUE;
  • 42.
    Why is theOptimizer not using my index? Index simple usage • Unique scan – find NOT NULL data that is unique in an index • Range scan – uses leading column of the index • Skip scan – first column of multi-column index not used Only used when all return columns in your query are in the index • Full scan – using the index to sort data • Fast full scan un-sorted uses index as source of table data • Join scan use two or more index instead of table for data source
  • 43.
    Reasons an indexis not used • You are searching for NULL (WHERE dept_no IS NULL) – indexes do not store NULL values • The number of rows you want to retrieve is not efficient when using an index Minimum of three blocks reads to get to one record, reading > 20% of the data, the index can become inefficient • Index clustering factor (related to range scans) • Clustering factor is per index • Related to how rows are stored in relation to the index columns IDX Root Block IDX Leaf Block TBL Data Block
  • 44.
    Index Clustering Cluster describesthe relationship to the data indexed and blocks stored Used when calculating if a RANGE SCAN would be helpful (BETWEEN) • close to the number of table blocks = data order matches the index key • close to the number of table rows = data scattered randomly across the blocks TBL Block ----------- Puri | Puri TBL Block ----------- Quinlan | Quinlan TBL Block ----------- Puri | Welles TBL Block ----------- Sheen | Puri TBL Block ----------- Lyon | Quinlan TBL Block ----------- Quinlan | Martin V.S. TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR ---------- --------------- --------- --------- ----------------- CUSTOMERS CUST_LNAME_IX 319 13 294 CUSTOMERS3 CUST3_LANME_IX 319 12 9 DEMO
  • 45.
    Wrapping Up Have aplan to find poor performing SQL Have your tuning tools ready to use! Know when each tool might be useful Oracle will tune a lot of things for you, but sometimes it wont Practice in non-production! 1. What is SQL tuning 2. What tools should I use 3. Explain Plan Lies 4. Statistics + Histograms = +1 5. Tuning Advisor + AWR top N SQL = +1 6. Why do SQL Profiles fail? 7. Create a SQL Baseline from cursor cache 8. How to make a SQL Patch 9. Playing with Optimizer 10. Why is my index not being used? (clustering)
  • 46.
  • 47.
    Keep Up ToSpeed With all Upcoming Events! https://events.viscosityna.com
  • 48.
  • 49.
    • Oracle Database19c SIG • Upcoming calls: Feb. 10, Mar. 10, Apr. 14 • IOUG Cloud Computing SIG • Upcoming calls: Feb. 16, Mar. 16, Apr. 20 • Oracle MAA Special Interest Group • Upcoming calls: Mar. 15 Anyone is welcome to join the SIG call. SIG membership is not required. 2 User Groups