Sie sind auf Seite 1von 8

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Common causes of poor SQL performance


Stale optimizer statistics
CBO requires representative statistics to optimize SQL execution
Not easy to determine when statistics are really stale
Not easy to determine when stale statistics are actually impacting plan selection
Missing access structures
Identifying useful indexes and MVs non-trivial
Difficult to ascertain performance impact of new structures on DMLs
Poor plan selection due to incorrect optimizer estimates
Manually hinting SQL a solution, but

Requires significant expertise


Is time consuming trial and error method
Does not work for packaged applications
Bad SQL design
Only real remedy is to restructure SQL
Requires expertise, time, application knowledge
Oracle SQL tuning is one of the most important areas of Oracle optimization.
IDENTIFY WAYS TO AVOID FULL TABLE SCAN ??
As a review, basic SQL tuning involves the resolution of these common execution access
issues:
Sub-optimal table join order - Identification of the best driving table is critical to SQL
performance. In an n-way table join, Oracle must join the tables together in a way to
minimize the intermediate result sets. Improper table join order is most often due to suboptimal CBO statistics, especially missing histogram statistics.
Sub-optimal table join methods - This is usually the choice between nested loop joins and
hash joins. For situations where you have a large pga_aggregate_target or hash_area_size
(pre-Oracle9i), certain joins operations may run far faster with hash joins.

Unnecessary large-table full-table scans (LT-FTS) - The CBO may decide to perform a fulltable scan when an index scan will retrieve the data with far less disk I/O. While not all
large-table full-table scans are unnecessary, the LT FTS is common where Oracle's Costbased SQL optimizer makes a sub-optimal access decision. When any of these conditions
are true, the optimizer may make poor decisions about the choice between a full-table
scan and an index scan, causing huge amount of unnecessary disk I/O.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Improper System parameters - Incorrect values for CBO initialization parameters


(optimizer_index_cost_adj, optimizer_index_caching)
Sub-optimal CBO statistics - This is usually the result of not analyzing with dbms_stats,
taking a too-small sample size, or failing to place histograms on skewed columns.
Missing indexes - If the WHERE clause of the query does not match an index, the CBO
may perform an unnecessary FTS.
Incorrect object parameters - Setting a table to a too-high value for dba_tables.degree will
make the CBO friendlier to full-table scans.
One important aspect of Oracle SQL tuning is the identification and inspection of full-table
scans.
However, Oracle distinguishes between the types of scans depending on the size of the table.

Large table, small table


There are two types of full-table scans, those against small tables STR-FTS and large-tables
LT-FTS. Let's start by exploring the threshold between large and small tables.
Remember, by small, we refer to the number of data blocks, not the number of rows. For
example, consider a table where dba_tables.avg_row_len = 32 and db_block_size = 32k. In
this case, a 3,000 row table would fit comfortably into only 4 data blocks. In a case like this,
it is almost fastest simply incur 4 physical gets and load the entire table into the data buffer.
In Oracle7 and Oracle8, the size of small tables was defined by the small_table_threshold
parameter, but in Oracle8i, the definition of a small table was changed to be any tables whose
total data blocks is greater than 2% of the number of blocks defined by db_cache_size. (You
can still change it with the now-hidden parameter _small_table_threshold). Because the
definition of a small table scales with the size of the SGA, a 200 block table may be
considered small on one database and large in another.

Tuning Large-table Full-table scans


The rule for evaluative and tuning LT-FTS is simple. We evaluate the query and see if index
access would result in less physical reads than the existing full-table scan. This usually
involves timing the execution speed for the query (with the set timing on command in
SQL*Plus) and timing the query with different index access plans:

Creating a function-based index - One common technique is to match the WHERE clause
of the query with a function-based index.
Using index hints - If the CBO does not have enough statistical information about an
index, you can force the CBO (temporarily) to use the index by adding an index hint to the
query.
Once the fastest execution plan is derived, the tuning professional will enforce the execution
plan by creating schema statistics to ensure that the CBO will always use the best index
access.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Tuning Small-table Full-table Scans


The problem with ST-FTS occurs when a popular table is referenced. Because the FTS
data blocks are not touched (pinged
to the MRU end of the buffer), ST-FTS rows age quickly from the buffer, requiring Oracle to
re-read them, over and over again.
n Oracle9i and beyond hidden parameter called _adaptive_direct_read that ensures that small
table scans are cached. However, it is still a good idea to identify these small tables yourself
and cache them in your KEEP pool.
The keep pool is a wonderful resource for ensuring that an object always resides in the data
buffer RAM, and this is one of the few ways to guarantee 10% caching.
Now that we see the benefit of caching frequently-referenced table and indexes, we see how
the KEEP pool is most important to small objects that are read into the data buffers via fulltable scans. For most objects in an OTLP system, aces is performed via an index, and only
small tables will have full-table scans.
Also, remember that frequently-referenced data blocks accessed via an index will tend to
remain in the data buffer without using the KEEP pool because they are pinged to the MRU end of the
buffer every time they are referenced.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Returning Data
The less data that is returned the smaller the Input/Output (I/O) cost of the query.
Therefore we should instruct a select statement to return only the columns from a table we really
need.
Only columns used for display purposes or those are used in further calculations should be returned.
Obtaining Data from Other Sources
Can any of the data be obtained without querying the database?
Before writing a select statement check that you do not already have the information you require
available in the form or module you are working in.
Obtaining the information from memory is far more efficient than querying the Database.
Outer Joins
Avoid use of outer joins in select statements if possible.
An outer join will force the optimizer to do a full table and return all the data from the table that the
outer join is on.
This will also vastly increase the amount of I/O that the server has to handle.
If you have a query that use a LEFT OUTER JOIN, check it carefully to be sure that is the type of
join you really want to use.
As you may know, a LEFT OUTER JOIN is used to create a result set that includes all of the rows
from the left table specified in the clause, not just the ones in which the joined columns match.
In addition, when a row in the left table has no matching rows in the right table, the result set row
Structure of Statements
Select statements, which return identical results set, can often be written in several different ways.
Each way can often cause the optimizer to execute the statement differently thus affecting the cost
and execution time.
The Distinct Clause
The distinct clause checks the returned result set for duplicate rows.
Carefully evaluate whether your query needs the DISTINCT clause or not. It slows down virtually
every query it is in. In addition, keep in mind that in some cases, duplicate results in a query are not
a problem. If this is the case, then don't use a DISTINCT clause.
However this query returns 4 rows. Adding the title_id column made more of the result set distinct. This
often catches many people out.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Using Functions on Columns in the WHERE Clause


Try to avoid using functions on columns in the where clause.
This will stop the optimizer from using an index to locate that data.
Multiple Tables in Statements
Try to keep the number of tables used in queries to a minimum.
It is recommended to have 5 as maximum number of tables that should be referenced in any query.
Due the nature of our schema there are going to be times when we are going to exceed this number.
EXISTS() v IN()
When you have a choice of using the IN or the EXISTS clause in your statements, you will generally
want to use the EXISTS clause, as it is more efficient and performs faster.
Not only that but using the IN clause can lead to the query producing unexpected results. The
following is an extract from an article published in SQL Server Professional.
Known problems with NOT IN()
Using NOT IN() has at least one known problem.
As I wrote here quite some time ago (see "The NOT IN subquery Trap" in the May 1998 issue),
there's a problem using NOT with the IN() predicate and a subquery.
The upshot is that if the list or subquery returned by the IN() predicate contains a NULL, then NOT
IN() causes the query to return no rows.
Because the EXISTS() predicate only returns True or False, it avoids the three-value logic that IN() is
exposed to, and effectively "tells the truth."

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

WildCard Operators (%)


Wildcard operators will not prevent the optimizer from using an index on your query provided that
they are preceded by constant character.
Operators
Never do a calculation on an indexed column (e.g., WHERE salary*5 > 50000), this would force the
optimizer to do a full table scan.
Index Hints
If you perform regular joins between two or more tables in your queries, performance will be
optimized if each of the joined columns has their own indexes. This includes adding indexes to the
columns in each table used to join the tables.
Do not index columns that are modified frequently.

UPDATE statements that modify indexed columns and INSERT or DELETE statements that
modify indexed tables take longer than if there were no index. These SQL statements modify data in
indexes as well as data in tables. They also generate additional undo and redo.
For maximum performance when joining two or more tables, the indexes on the columns to be joined
should have the same data type.
For best join performance, the indexes on the columns being joined should be numeric data types,
not CHAR or VARCHAR. The overhead is lower and join performance is faster.
Ordering of SQL Statements
Given the above information it is clear that the order in which we execute these statements
influences how long locks will be held for.
Obviously we want to hold as few locks as possible for the shortest possible time.
Once a lock is taken out it will be held for the duration of the transaction so the key is to execute
statements that lock small amounts of data first and leave the ones that lock large amounts till the
end.
The general order in which statements should be executed in a transaction is shown below.

SELECT
INSERT
DELETE
UPDATE

Updates can lock large amounts of data, sometimes entire pages or tables, we want these locks to
be held for the shortest possible duration.
Therefore updates of large amounts of data should occur at the end of transactions. This is where
the time between the lock being taken and the transaction completing is shortest.
Deletes, like updates, can lock entire pages or tables so should be placed towards the end of a
transaction.
However they should occur before updates, as the data affected by them will be removed at the end
of the transaction, so other users are less likely to want to access it.
Inserts should be placed before deletes and updates as they only lock the row they are inserting.
This will have less of an affect on others users as they probably dont know that this data exists yet
so will not be attempting to access it.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Selects statements do not modify any data so there is no need to place them in transactions at all.
However if it is unavoidable they should be placed as close to the beginning of the transaction as
possible.
Select statements take time to execute so therefore any locks that have already been taken out will
be held while the statement executes. That is why they are better positioned as early as possible, as
fewer locks will have occurred by then.
Length of Transactions
The longer a transaction is, then the longer the locks will be held for. Therefore it is important that
transactions are kept as short as possible. Removing all select statements from inside the
transaction can help. You should also obtain all the information you need to modify, create or delete
before you start a transaction. Also keep the amount of data manipulation within the transaction to
an absolute minimum, using bulk updates/deletes/inserts is advisable.
Frequently Accessed Data
Statements that modify tables that are most frequently accessed should also be placed at the end of
transactions. Any locks held on these types of tables are more likely to be blocking other users from
accessing the data. Therefore we need to reduce the time that these locks are held by placing them
as late as possible in the transaction.
PL/SQL Performance Tuning Tips
Without PL/SQL, Oracle must process SQL statements one at a time. Each SQL statement results in
another call to Oracle and higher performance overhead. In a networked environment, the overhead
can become significant. Every time a SQL statement is issued, it must be sent over the network,
creating more traffic.
With PL/SQL, an entire block of statements can be sent to Oracle at one time. This can drastically
reduce communication between your application and Oracle.
To improve package performance is to pin frequently used packages in the shared memory pool.
When a package is pinned, it is not aged out by the least recently used (LRU) algorithm that Oracle
normally uses. The package remains in memory no matter how full the pool gets or how frequently
you access the package.
If the SQL statement affects four or more database rows, the use of bulk binds (FORALL) can
improve performance considerably.
Native dynamic SQL is easier to use and much faster than the DBMS_SQL (Dynamic PL/SQL) package.
T-SQL Performance Tuning Tips
Always include a WHERE clause in your SELECT statement to narrow the number of rows returned.
If you don't use a WHERE clause, then SQL Server will perform a table scan of your table and return
all of the rows.
In some case you may want to return all rows, and not using a WHERE clause is appropriate in this
case.
Try to avoid WHERE clauses that are non-sargable.
The term "sargable" (which is in effect a made-up word) comes from the pseudo-acronym "SARG",
which stands for "Search Arguments," which refers to a WHERE clause that compares a column to a
constant value.
Non-sargable search arguments in the WHERE clause, such as "IS NULL", "<>", "!=", "!>", "!<",
"NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'" generally prevents (but not
always) the query optimizer from using an index to perform a search.

SQL OPTIMIZATION TIPS AND GOOD PRACTISES

Eighteen tips for avoiding problematic queries


These tips provide a solid foundation for two outcomes: making a SQL statement to perform
better, and determining that nothing else can be done in this regard (i.e., you have done all
you can with the SQL statement, time to move on to another area).
The 18 tips are listed below.
1. Avoid Cartesian products

2. Avoid full table scans on large tables


3. Use SQL standards and conventions to reduce parsing
4. Lack of indexes on columns contained in the WHERE clause
5. Avoid joining too many tables
6. Monitor V$SESSION_LONGOPS to detect long running operations
7. Use hints as appropriate
8. Use the SHARED_CURSOR parameter
9. Use the Rule-based optimizer if I is better than the Cost-based optimizer
10. Avoid unnecessary sorting
11. Monitor index browning (due to deletions; rebuild as necessary)
12. Use compound indexes with care (Do not repeat columns)
13. Monitor query statistics
14. Use different tablespaces for tables and indexes (as a general rule; this is old-school
somewhat, but the main point is reduce I/O contention)
15. Use table partitioning (and local indexes) when appropriate
(partitioning is an extra cost feature)
16. Use literals in the WHERE clause (use bind variables)
17. Keep statistics up to date
18. Ensure proper constraints are selected --- replace SQL with SP if neccessary

Das könnte Ihnen auch gefallen