1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle SQL tuning pocket re

90 75 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 90
Dung lượng 829,53 KB

Nội dung

Oracle SQL Tuning Pocket Reference By Mark Gurry Publisher : O'Reilly Pub Date : January 2002 ISBN : 0-596-00268-8 • Table of Pages : 108 Contents • Index • Reviews • Reader Reviews • Errata Copyright Chapter Oracle SQL TuningPocket Reference Section 1.1 Introduction Section 1.2 The SQL Optimizers Section 1.3 Rule-Based Optimizer Problems and Solutions Section 1.4 Cost-Based Optimizer Problems and Solutions Section 1.5 Problems Common to Rule and Cost with Solutions Section 1.6 Handy SQL Tuning Tips Section 1.7 Using SQL Hints Section 1.8 Using DBMS_STATS to Manage Statistics Section 1.9 Using Outlines for Consistent Execution Plans Index Chapter Oracle SQL TuningPocket Reference Section 1.1 Introduction Section 1.2 The SQL Optimizers Section 1.3 Rule-Based Optimizer Problems and Solutions Section 1.4 Cost-Based Optimizer Problems and Solutions Section 1.5 Problems Common to Rule and Cost with Solutions Section 1.6 Handy SQL Tuning Tips Section 1.7 Using SQL Hints Section 1.8 Using DBMS_STATS to Manage Statistics Section 1.9 Using Outlines for Consistent Execution Plans 1.1 Introduction This book is a quick-reference guide for tuning Oracle SQL This is not a comprehensive Oracle tuning book The purpose of this book is to give you some light reading material on my "real world" tuning experiences and those of my company, Mark Gurry & Associates We tune many large Oracle sites Many of those sites, such as banks, large financial institutions, stock exchanges, and electricity markets, are incredibly sensitive to poor performance With more and more emphasis being placed on 24/7 operation, the pressure to make SQL perform in production becomes even more critical When a new SQL statement is introduced, we have to be absolutely sure that it is going to perform When a new index is added, we have to be certain that it will not be used inappropriately by existing SQL statements This book addresses these issues Many sites are now utilizing third-party packages such as Peoplesoft, SAP, Oracle Applications, Siebel, Keystone, and others Tuning SQL for these applications must be done without placing hints on SQL statements, because you are unauthorized to touch the application code Obviously, for similar reasons, you can't rewrite the SQL But don't lose heart; there are many tips and tricks in this reference that will assist you when tuning packaged software This book portrays the message, and my firm belief, that there is always a way of improving your performance to make it acceptable to your users 1.1.1 Acknowledgments Many thanks to my editor, Jonathan Gennick His feedback and suggestions have added significant improvements and clarity to this book A hearty thanks to my team of technical reviewers: Sanjay Mishra, Stephen Andert, and Tim Gorman.Thanks also to my Mark Gurry & Associates consultants for their technical feedback Special thanks to my wife Juliana for tolerating me during yet another book writing exercise 1.1.2 Caveats This book does not cover every type of environment, nor does it cover all performance tuning scenarios that you will encounter as an Oracle DBA or developer I can't stress enough the importance of regular hands-on testing in preparation for being able to implement your performance tuning recommendations 1.1.3 Conventions UPPERCASE Indicates a SQL keyword lowercase Indicates user-defined items such as tablespace names and datafile names Constant width Used for examples showing code Constant width bold Used for emphasis in code examples [] Used in syntax descriptions to denote optional elements {} Used in syntax descriptions to denote a required choice | Used in syntax descriptions to separate choices 1.1.4 What's New in Oracle9i It's always exciting to get a new release of Oracle This section briefly lists the new Oracle9i features that will assist us in getting SQL performance to improve even further than before The new features are as follows: • A new INIT.ORA parameter, FIRST_ROWS_n, that allows the cost-based optimizer to make even better informed decisions on the optimal execution path for an OLTP application The n can equal 1, 10, 100, or 1,000 If you set the parameter to FIRST_ROWS_1, Oracle will determine the optimum execution path to return one row; FIRST_ROWS_10 will be the optimum plan to return ten rows; and so on • There is a new option called SIMILAR for use with the CURSOR_SHARING parameter The advantages of sharing cursors include reduced memory usage, faster parses, and reduced latch contention SIMILAR changes literals to bind variables, and differs from the FORCE option in that similar statements can share the same SQL area without resulting in degraded execution plans • There is a new hint called CURSOR_SHARING_EXACT that allows you to share cursors for all statements except those with this hint In essence, this hint turns off cursor sharing for an individual statement • There is a huge improvement in overcoming the skewness problem The skewness problem comes about because a bind variable is evaluated after the execution plan is decided If you have 1,000,000 rows with STATUS = `C' for Closed, and 100 rows with STATUS = `O' for Open, Oracle should use the index on STATUS when you query for STATUS = `O', and should perform a full table scan when you query for STATUS = `C' If you used bind variables prior to Oracle9i, Oracle would assume a 50/50 spread for both values, and would use a full table scan in either case Oracle 9i determines the value of the bind variable prior to deciding on the execution plan Problem solved! • You can nowidentify unused indexes using the ALTER INDEX MONITOR USAGE command • You can now use DBMS_STATS to gather SYSTEM statistics, including a system's CPU and I/O usage You may find that disks are a bottleneck, and Oracle will then have the information to adjust the execution plans accordingly • There are new hints, including NL_AJ, NL_SJ, FACT, NO_FACT, and FIRST_ROWS(n) All are described in detail in Section 1.7 of this reference • Outlines were introduced with Oracle8i to allow you to force execution plans (referred to as "outlines") for selected SQL statements However, it was sometimes tricky to force a SQL statement to use a particular execution path Oracle9i provides us with the ultimate: we can now edit the outline using the DBMS_OUTLN_EDIT package 1.2 The SQL Optimizers Whenever you execute a SQL statement, a component of the database known as the optimizer must decide how best to access the data operated on by that statement Oracle supports two optimizers: the rule-base optimizer (which was the original), and the cost-based optimizer To figure out the optimal execution path for a statement, the optimizers consider the following: • The syntax you've specified for the statement • Any conditions that the data must satisfy (the WHERE clauses) • The database tables your statement will need to access • All possible indexes that can be used in retrieving data from the table • The Oracle RDBMS version • The current optimizer mode • SQL statement hints • All available object statistics (generated via the ANALYZE command) • The physical table location (distributed SQL) • INIT.ORA settings (parallel query, async I/O, etc.) Oracle gives you a choice of two optimizing alternatives: the predictable rule-based optimizer and the more intelligent cost-based optimizer 1.2.1 Understanding the Rule-Based Optimizer The rule-based optimizer (RBO) uses a predefined set of precedence rules to figure out which path it will use to access the database The RDBMS kernel defaults to the rule-based optimizer under a number of conditions, including: • OPTIMIZER_MODE = RULE is specified in your INIT.ORA file • OPTIMIZER_MODE = CHOOSE is specified in your INIT.ORA file, andno statistics exist for any table involved in the statement • An ALTER SESSION SET OPTIMIZER_MODE = RULE command has been issued • An ALTER SESSION SET OPTIMIZER_MODE = CHOOSEcommand has been issued, and no statistics exist for any table involved in the statement • The rule hint (e.g., SELECT /*+ RULE */ .) has been used in the statement The rule-based optimizer is driven primarily by 20 condition rankings, or "golden rules." These rules instruct the optimizer how to determine the execution path for a statement, when to choose one index over another, and when to perform a full table scan These rules, shown in Table 1-1, are fixed, predetermined, and, in contrast with the cost-based optimizer, not influenced by outside sources (table volumes, index distributions, etc.) Table 1-1 Rule-based optimizer condition rankings Rank Condition ROWID = constant Cluster join with unique or primary key = constant Hash cluster key with unique or primary key = constant Entire Unique concatenated index = constant Unique indexed column = constant Entire cluster key = corresponding cluster key of another table in the same cluster Hash cluster key = constant Entire cluster key = constant Entire non-UNIQUE CONCATENATED index = constant 10 Non-UNIQUE index merge 11 Entire concatenated index = lower bound 12 Most leading column(s) of concatenated index = constant 13 14 Indexed column between low value and high value or indexed column LIKE "ABC%" (bounded range) Non-UNIQUE indexed column between low value and high value or indexed column like `ABC%' (bounded range) 15 UNIQUE indexed column or constant (unbounded range) 16 Non-UNIQUE indexed column or constant (unbounded range) 17 Equality on non-indexed = column or constant (sort/merge join) 18 MAX or MIN of single indexed columns 19 ORDER BY entire index 20 Full table scans While knowing the rules is helpful, they alone not tell you enough about how to tune for the rulebased optimizer To overcome this deficiency, the following sections provide some information that the rules don't tell you 1.2.1.1 What the RBO rules don't tell you #1 Only single column indexes are ever merged Consider the following SQL and indexes: SELECT col1, FROM emp WHERE emp_name = 'GURRY' AND emp_no = 127 AND dept_no = 12 Index1 (dept_no) Index2 (emp_no, emp_name) The SELECT statement looks at all three indexed columns Many people believe that Oracle will merge the two indexes, which involve those three columns, to return the requested data In fact, only the two-column index is used; the single-column index is not used While Oracle will merge two single-column indexes, it will not merge a multi-column index with another index There is one thing to be aware of with respect to this scenario If the single-column index is a unique or primary key index, that would cause the single-column index to take precedence over the multicolumn index Compare rank with rank in Table 1-1 Oracle8i introduced a new hint, INDEX_JOIN, that allows you to join multi-column indexes 1.2.1.2 What the RBO rules don't tell you #2 If all columns in an index are specified in the WHERE clause, that index will be used in preference to other indexes for which some columns are referenced For example: SELECT col1, FROM emp WHERE emp_name = 'GURRY' AND emp_no = 127 AND dept_no = 12 Index1 (emp_name) Index2 (emp_no, dept_no, cost_center) In this example, only Index1 is used, because the WHERE clause includes all columns for that index, but does not include all columns for Index2 1.2.1.3 What the RBO rules don't tell you #3 If multiple indexes can be applied to a WHERE clause, and they all have an equal number of columns specified, only the index created last will be used For example: SELECT col1, FROM emp WHERE emp_name = 'GURRY' AND emp_no = 127 AND dept_no = 12 AND emp_category = 'CLERK' Index1 (emp_name, emp_category) Created 4pm Feb 11th 2002 Index2 (emp_no, dept_no) Created 5pm Feb 11th 2002 In this example, only Index2 is used, because it was created at p.m and the other index was created at p.m This behavior can pose a problem, because if you rebuild indexes in a different order than they were first created, a different index may suddenly be used for your queries To deal with this problem, many sites have a naming standard requiring that indexes are named in alphabetical order as they are created Then, if a table is rebuilt, the indexes can be rebuilt in alphabetical order, preserving the correct creation order You could, for example, number your indexes Each new index added to a table would then be given the next number 1.2.1.4 What the RBO rules don't tell you #4 If multiple columns of an index are being accessed with an = operator, that will override other operators such as LIKE or BETWEEN Two ='s will override two ='s and a LIKE For example: SELECT col1, FROM emp WHERE emp_name LIKE 'GUR%' AND emp_no = 127 AND dept_no = 12 AND emp_category = 'CLERK' AND emp_class = 'C1' Index1 (emp_category, emp_class, emp_name) Index2 (emp_no, dept_no) In this example, only Index2 is utilized despite Index1 having three columns accessed and Index2 having only two column accessed 1.2.1.5 What the RBO rules don't tell you #5 A higher percentage of columns accessed will override a lower percentage of columns accessed So generally, the optimizer will choose to use the index from which you specify the highest percentage of columns However, as stated previously, all columns specified in a unique or primary key index will override the use of all other indexes For example: SELECT col1, FROM emp WHERE emp_name = 'GURRY' AND emp_no = 127 AND emp_class = 'C1' Index1 (emp_name, emp_class, emp_category) Index2 (emp_no, dept_no) In this example, only Index1 is utilized, because 66% of the columns are accessed Index2 is not used because a lesser 50% of the indexed columns are used 1.2.1.6 What the RBO rules don't tell you #6 If you join two tables, the rule-based optimizer needs to select a driving table The table selected can have a significant impact on performance, particularly when the optimizer decides to use nested loops A row will be returned from the driving table, and then the matching rows selected from the other table It is important that as few rows as possible are selected from the driving table The rule-based optimizer uses the following rules to select the driving table: • A unique or primary key index will always cause the associated table to be selected as the driving table in front of a non-unique or non-primary key index • An index for which you apply the equality operator (=) to all columns will take precedence over indexes from which you use only some columns, and will result in the underlying table being chosen as the driving table for the query • The table that has a higher percentage of columns in an index will override the table that has a lesser percentage of columns indexed • A table that satisfies one two-column index in the WHERE clause of a query will be chosen as the driving table in front of a table that satisfies two single-column indexes • If two tables have the same number of index columns satisfied, the table that is listed last in the FROM clause will be the driving table In the SQL below, the EMP table will be the driving table because it is listed last in the FROM clause • • • • SELECT FROM DEPT d, EMP e WHERE e.emp_name = 'GURRY' AND d.dept_name = 'FINANCE' AND d.dept_no = e.dept_no 1.2.1.7 What the RBO rules don't tell you #7 If a WHERE clause has a column that is the leading column on any index, the rule-based optimizer will use that index The exception is if a function is placed on the leading index column in the WHERE clause For example: SELECT col1, FROM emp WHERE emp_name = 'GURRY' Index1 (emp_name, emp_class, emp_category) Index2 (emp_class, emp_name, emp_category) Interestingly, if all things are equal, the cost-based optimizer will use the left to right order in the FROM clause, which is the exact reverse of the rule-based optimizer However, in a complex query, it is rare to find all things equal in the WHERE clause Use this hint to guarantee the join order ORDERED_PREDICATES Causes WHERE clause predicates to be evaluated in the order in which they are listed in the WHERE clause If you not specify ORDERED_PREDICATES, Oracle will evaluate subqueries and user functions first SELECT WHERE /*+ ORDERED_PREDICATES */ This is the only hint that goes in the WHERE clause rather than after the keyword that begins the statement PARALLEL(table [,integer] [,integer]) Explicitly specifies the actual number of concurrent query servers that will be used to service the query The first optional value specifies the degree of parallelism (number of query servers) for the table This is the number of processes assigned to perform the scan of the specified table in parallel on a single instance The second optional value specifies the number of Oracle parallel server instances to split the query across If you specify PARALLEL(EMP, 2), there will be four parallel query processes running on two separate parallel server instances If no parameters are specified, the default (calculated) degree of parallelism and number of parallel servers is sourced from the parameters specified in the INIT.ORA file The hint can be used for selects, updates, deletes, and inserts To get performance improvements using the parallel hint, your datafiles must be striped across multiple disks Don't set the degree of parallelism higher than the number of disks that the table is striped over Having multiple processors will make the operation run even faster, but only if the table is striped SELECT /*+ PARALLEL (x 4) */ COUNT(*) FROM x; SELECT /*+ PARALLEL (x 2) */ COUNT(*) FROM x; UPDATE /*+ PARALLEL (x 4) */ x SET position = position+1; DELETE /*+ parallel(x 4) */ from x; INSERT INTO x SELECT /*+ PARALLEL(winners 4) */ * FROM winners; PARALLEL_INDEX(table, index, degree of parallelism, cluster split) Allows you to parallelize index range scans for partitioned indexes Also allows the work to be done across multiple instances of a parallel server architecture The following example tells the optimizer to utilize parallel index processing on the EMP table, which is partitioned, to use the EMP_NDX index, and to run at a parallel degree of four over two Oracle parallel server instances SELECT /*+ PARALLEL_INDEX(emp, emp_ndx, 4, 2) */ PQ_DISTRIBUTE(table [Outer Distribution] [Inner Distribution]) Used to improve parallel join performance There are six possibilities for distribution hints, as listed in Table 1-6 SELECT /*+ USE_HASH(o) PQ_DISTRIBUTE(o HASH, HASH) */ COUNT(*) FROM winners w, owners o WHERE w.owner = o.owner; Table 1-6 PQ_DISTRIBUTE combinations Distribution Meaning combination Uses a hash function on the join keys for each query server process Can be used HASH, HASH for a hash join or sort merge join Works best when tables are approximately the same size BROADCAST, Broadcasts all rows of the outer table to each of the parallel query servers Use NONE this when the outer table is considerably smaller than the inner table NONE, Broadcasts all rows of the inner table to each of the parallel query servers Use BROADCAST this option when the size of the inner table is much smaller than the outer table Maps the rows of the outer table using the partitioning of the inner table The PARTITION, inner table must be partitioned and equi-joined on the join keys This option NONE works most effectively if the number of partitions in the outer table is equal to the number of parallel query processes utilized Maps the rows of the inner table using the partitioning of the outer table The NONE, outer table must be partitioned on the join keys Use this option when the number PARTITION of partitions on the outer table is equal to the number of parallel query servers Causes each query server to perform a join operation between a pair of matching NONE, NONE partitions, one from each table Both tables must be equi-partitioned for this option to be used effectively PUSH_PRED(table) Pushes the join predicate for a table into an inline view Doing so can sometimes help the cost-based optimizer make better decisions SELECT /*+ PUSH_PRED(v) */ count(*) FROM horses h, (SELECT w.horse_name, o.owner, w.position FROM winners w, owners o WHERE w.owner = o.owner) v WHERE h.horse_name = v.horse_name AND v.position = The difference in the execution plan for the example is that the HORSE_NAME in the WHERE clause is joined to the inline view as part of the inline view selection PUSH_SUBQ Forces nonmerged subqueries to be evaluated as early as possible in the execution plan Nonmerged subqueries are normally executed as the last step of an execution plan This hint has no effect on a subquery if the subquery is over a remote table (as in a distributed SQL statement), or if the subquery uses a merge join SELECT count(*) FROM horses WHERE EXISTS ( SELECT /*+ PUSH_SUBQ */ 'x' FROM horse_owners WHERE owner LIKE '%Lombardo%' AND horses.horse_name= horse_owners.horse_name) REWRITE Allows Oracle to utilize materialized views based on a selected table In the example that follows, we have a table that contains horse race results We have created a materialized view that stores the OWNER, HORSE_NAME, POSITION, and the COUNT(*) for each of those combinations CREATE MATERIALIZE VIEW LOG ON RESULTS WITH ROWID, PRIMARY KEY (HORSE_NAME, OWNER, RACE_DATE) INCLUDING NEW VALUES; CREATE MATERIALIZED VIEW winning_horse_owners_vw USING INDEX REFRESH ON COMMIT ENABLE QUERY REWRITE AS SELECT horse_name, owner, position, COUNT(*) FROM results GROUP BY horse_name, owner, position; In order for this materialized view to be useful, you must have the INIT.ORA parameter QUERY_REWRITE_ENABLED=TRUE, and the schema MUST HAVE the privilege QUERY REWRITE assigned For example: GRANT QUERY REWRITE TO HROA; The SQL query shown next is able to obtain all of the data it requires from the view, and therefore the optimizer will use the view in preference to the table, despite the SELECT being made against the table SELECT /*+ REWRITE */ horse_name, owner, position, COUNT(*) FROM results GROUP BY horse_name, owner, position; ROWID(table) Forces a table scan by ROWID for the specified table The rowid is the physical disk address of the row SELECT /*+ ROWID(a) */ ename FROM emp a WHERE rowid > 'AAAGJ2AAIAAABn4AAA' AND surname like 'GURR%' RULE Uses the rule-based optimizer for the current statement block You can achieve the same effect by having the CHOOSE option specified for the INIT.ORA parameter OPTIMIZER_MODE, and not analyzing the tables and indexes used in the SELECT statement STAR Forces the largest table to be last in the join order Typically the other tables should be lookup or reference tables This hint is used extensively in data warehouse applications STAR is only effective when you are joining at least three tables SELECT /*+ STAR */ h.horse_name, o.owner, r.position, r.location, r.race_date FROM results r, horses h, owners o WHERE h.horse_name like 'WI%' AND h.horse_name = r.horse_name AND r.owner = o.owner; STAR_TRANSFORMATION Works on fact and dimension tables, and is similar to the STAR hint The major difference is that it allows the cost-based optimizer to decide if it is worth transforming the statement into a new statement before determining the execution plan By "transforming," I mean that the statement is broken into a number of subqueries that are able to take advantage of bitmap indexes To use this hint, it is essential that you have STAR_TRANSFORMATION_ENABLED=TRUE in your INIT.ORA file The most pronounced difference between this hint and the STAR hint is that the STAR_TRANSFORMATION will often combine bitmap indexes on the various fact table columns rather than using a Cartesian join This is achieved by breaking the statement into subquery pieces SELECT /*+ STAR_TRANSFORMATION */ UNNEST Merges the body of a subquery into the body of the main statement, which can often improve optimizer decision making UNNEST can only be used when the session parameter UNNEST_SUBQUERY=TRUE SELECT /*+ UNNEST */ count(*) FROM horses WHERE horse_name LIKE 'M%' AND horse_name NOT IN ( SELECT horse_name FROM horse_owners WHERE owner LIKE '%Lombardo%'); USE_CONCAT Forces the optimizer to take OR conditions in the WHERE clause and convert them to a UNION ALL query operation In an example such as the one that follows, the index is scanned twice, once for each condition on the two sides of the OR The data is then joined into one result set via a concatenation operation SELECT /*+ USE_CONCAT */ COUNT(*) FROM horse_owners WHERE identifier < 10 OR identifier > 20 USE_HASH (table) A hash join is an alternative to a nested loop A hash table is created in memory of the smallest table, and then the other table(s) is scanned, with its rows being compared to the hash A hash join will run faster than a merge join (sort merge) if memory is adequate to hold the entire table that is being hashed The entire join operation must be performed before a single row is returned to the user Therefore, hash joins are usually used for reporting and batch processing SELECT /*+ USE_HASH(w o) */ count(*) FROM winners w, owners o WHERE w.owner like 'Mr M A Gurry' AND w.owner= o.owner AND o.suburb = 'RICHMOND' A hash join can only be used for equality-based joins (=), and not for range-based joins (=) A merge join is often appropriate when a hash join cannot be used Don't confuse the HASH hint with USE_HASH USE_MERGE(table) A merge join is an alternative to nested loop and hash joins All tables are sorted, unless all of the columns in the WHERE clause are contained within an index This sort can be expensive and it explains why a hash join will often run faster then a merge join SELECT /*+ USE_MERGE(w o) */ count(*) FROM winners w, owners o WHERE w.owner like 'Mr M A Gurry' AND w.owner < o.owner AND o.suburb = 'RICHMOND' The entire set of data must be returned before a single row is returned to the user Therefore hash joins are usually used for reporting and batch processing Don't confuse the MERGE hint and USE_MERGE Merge joins work effectively for equality-based joins as well as for range-based joins Merge joins also often run much faster than a hash join when all of the columns in the WHERE clause are pre-sorted in an index USE_NL(table) Forces the optimizer to join the specified table to another table (or subquery) using a nested loop join The specified table is joined as the inner table of the nested loops Nested loop joins are faster than sort/merge or hash joins at retrieving the first row of a query statement Online screens should definitely use nested loops, because data will be returned immediately As a rule of thumb, if less than 10% of the rows are returned from the tables, consider using nested loops Use hash joins or sort merges if 10% or more of the rows are being returned SELECT /*+ USE_NL(w o) */ count(*) FROM winners w, owners o WHERE w.owner like 'Mr M A Gurry' AND w.owner= o.owner AND o.suburb = 'RICHMOND' 1.8 Using DBMS_STATS to Manage Statistics DBMS_STATS was introduced in Oracle8i; it provides critical functionality for the cost-based optimizer, including speeding the analyze process, allowing statistics to be modified, reverting back to previous statistics, and copying statistics from one schema (or database) to another 1.8.1 Using DBMS_STATS to Analyze Faster DBMS_STATS offers two powerful ways of speeding up the analyze process First, you can analyze tables (not indexes) in parallel Second, you can analyze only tables and their associated indexes that have had more than 10% of their rows modified through INSERT, UPDATE, or DELETE operations To analyze a schema's tables in parallel, use a command such as the following: EXECUTE SYS.DBMS_STATS.GATHER_SCHEMA_STATS (OWNNAME=> 'HROA', ESTIMATE_PERCENT=>10, DEGREE=>4, CASCADE=>TRUE); This command estimates statistics for the schema HROA The DEGREE value specifies the degree of parallelism to use CASCADE=>TRUE causes the indexes for each table to be analyzed as well DBMS_STATS has a GATHER STALE option that will only analyze tables that have had more than 10% of their rows changed To use it, you first need to turn on monitoring for your selected tables For example: ALTER TABLE WINNERS MONITORING; You can observe information about the number of table changes for a given table by selecting from the USER_TAB_MODIFICATIONS view You can see if monitoring is turned on for a particular table by selecting the MONITORING column from USER_TABLES With monitoring enabled, you can run the GATHER_SCHEMA_STATS package using the GATHER STALE option: EXECUTE SYS.DBMS_STATS.GATHER_SCHEMA_STATS (OWNNAME=> 'HROA', ESTIMATE_PERCENT=>10, DEGREE=>4, CASCADE=>TRUE, OPTIONS=>'GATHER STALE'); Because GATHER_STALE is specified, tables will only be analyzed if they have had 10% or more of their rows changed since the previous analyze 1.8.2 Copying Statistics Using DBMS_STATS DBMS_STATS gives you the ability to copy statistics from one schema to another, or from one database to another, using the following procedure: Step Create a table to store the statistics, if you have not already done so: EXECUTE SYS.DBMS_STATS.CREATE_STATS_TABLE (OWNNAME=> 'HROA', STATTAB=>'HROA_STAT_TABLE'); Step Populate the table with the statistics from the schema that you are copying from: EXECUTE SYS.DBMS_STATS.EXPORT_SCHEMA_STATS (OWNNAME=> 'HROA', STATTAB=>'HROA_STAT_TABLE', STATID=> 'HROA_21SEP_2001'); Step If you are copying statistics to a different database, such as from production to development, export and import that statistics table as required: exp hroa/secret@prod file=stats tables=hroa_stat_table imp hroa/secret@dev file=stats tables=hroa_stat_table Step Populate the statistics in the target schema's dictionary In the following example, statistics are being loaded for the schema HROA_TEST from the table named HROA_STAT_TABLE: EXECUTE SYS.DBMS_STATS.IMPORT_SCHEMA_STATS (OWNNAME=> 'HROA_TEST', STATTAB=>'HROA_STAT_TABLE', STATID=> 'HROA_21SEP_2001', STATOWN=> 'HROA'); 1.8.3 Manipulating Statistics Using DBMS_STATS Often you will want to determine if the cost-based optimizer will use the same execution plan in production as it is using in the current development and test databases You can achieve this by using DBMS_STATS.SET_TABLE_STATS to modify the statistics for a table in your development or for a test database to match those in your production database The optimizer uses the number of rows, number of blocks, and number of distinct values for a column to determine whether an index or a full table scan should be used The following example assumes that your production WINNERS table is going to have 1,000,000 rows in 6,000 blocks: EXECUTE SYS.DBMS_STATS.SET_TABLE_STATS (OWNNAME=> 'HROA_DEV', TABNAME=>'WINNERS', NUMROWS=> 1000000, NUMBLKS=> 6000); Regardless of how many rows you really have in your test database, the cost-based optimizer will now behave as if there were 1,000,000 The optimizer also uses the number of distinct values for each column to decide on index usage If the number of distinct values is less than 10% of the number of rows in the table, the optimizer will usually decide to perform a full table scan in preference to using an index on the table column Change the percentage of distinct values for a column as follows: EXECUTE SYS.DBMS_STATS.SET_COLUMN_STATS (OWNNAME=> 'F70PSOFT', TABNAME=>'PS_LED_AUTH_TBL', COLNAME=>'OPRID', DISTCNT=>971); 1.8.4 Reverting to Previous Statistics Usually, re-analyzing a schema and specifying a high percentage of rows for the sample size will improve performance Unfortunately, the occasional hiccup will occur when you re-analyze tables Sometimes the new statistics produce much worse execution plans than before You can avoid the risk of a major screw up by using the DBMS_STATS package to save a copy of your current statistics just in case you need to restore them later This requires the following steps: Step Export your schema statistics to your statistics table If you don't already have a statistics table, you can create it using the DBMS_STATS.CREATE_STATS_TABLE procedure The export is performed as follows: EXECUTE SYS.DBMS_STATS.EXPORT_SCHEMA_STATS (OWNNAME=> 'HROA', STATTAB=> 'HROA_STAT_TABLE', STATID=> 'PRE_21SEP_2001'); Step Gather your new statistics: EXECUTE SYS.DBMS_STATS.GATHER_SCHEMA_STATS (OWNNAME=> 'HROA', ESTIMATE_PERCENT=>10, DEGREE=>4, CASCADE=>TRUE); Step If there are problems with unsuitable execution paths being selected as a result of the new statistics, revert back to the previous statistics by loading the previous statistics from the statistics table: EXECUTE SYS.DBMS_STATS.IMPORT_SCHEMA_STATS (OWNNAME=> 'HROA', STATTAB=>'HROA_STAT_TABLE', STATID=> 'PRE_21SEP_2001'); 1.9 Using Outlines for Consistent Execution Plans Oracle introduced outlines in Oracle8i to allow you to have a pre-defined execution plan for a SQL statement Consistency can then be provided without changing the actual SQL Outlines can be used for packaged software to provide execution plan stability without the need to change the application's SQL 1.9.1 Recording Outlines An outline is nothing more than a stored execution plan that Oracle uses rather than computing a new plan based on current table statistics Before you can use outlines, you must record some You can record outlines for a single statement, for all statements issued by a single session, or for all statements issued to an instance 1.9.1.1 Recording an outline for a SQL statement You can record the outlines for a particular statement using the CREATE OR REPLACE OUTLINE command as follows: CREATE OR REPLACE OUTLINE aug0901 FOR CATEGORY harness_racing ON select * from winners where owner > 'G%'; In this example, aug0901 is the name of the specific outline being created, and harness_racing is the name of a category, or group, or related outlines 1.9.1.2 Recording outlines for all of a session's SQL You can turn on the recording of outlines for a session by using the ALTER SESSION CREATE_STORED_OUTLINES command Specify a category name to save outlines into a specific category: ALTER SESSION SET CREATE_STORED_OUTLINES =GENERAL_LEDGER; Specify TRUE to record outlines in the default category, which is named DEFAULT: ALTER SESSION SET CREATE_STORED_OUTLINES=TRUE; Specify FALSE to disable the recording of stored outlines: ALTER SESSION SET CREATE_STORED_OUTLINES=FALSE; 1.9.1.3 Recording outlines for the whole system The syntax to turn on recording of outlines system-wide is very similar to the ALTER SESSION syntax Simply use ALTER SYSTEM instead of ALTER SESSION For example: ALTER SYSTEM SET CREATE_STORED_OUTLINES =GENERAL_LEDGER NOOVERRIDE; The NOOVERRIDE option will avoid the complete deletion of the GENERAL_LEDGER outlines in the example shown If NOOVERRIDE had not been specified, all statements stored in the GENERAL_LEDGER category would have been removed When NOOVERRIDE is specified, new statements have their outlines added to the existing category If the same statement appears with an updated outline, the new outline will be stored Likewise, to turn off outline recording system-wide: ALTER SYSTEM SET CREATE_STORED_OUTLINES=FALSE; 1.9.2 Enabling Outlines You now have your outlines stored away In order for Oracle to use them, you must enable them 1.9.2.1 Enabling outlines for a session You can enable the usage of outlines for a session by setting the ALTER SESSION USE_STORED_OUTLINES command Specify a category name to use the outlines in that category: ALTER SESSION SET USE_STORED_OUTLINES =GENERAL_LEDGER; Specify TRUE to use outlines from the DEFAULT category: ALTER SESSION SET USE_STORED_OUTLINES= TRUE; Specify FALSE to disable (turn off) the use of outlines: ALTER SESSION SET USE_STORED_OUTLINES= FALSE; 1.9.2.2 Enabling outlines for the whole system To enable outlines system-wide, use ALTER SYSTEM instead of ALTER SESSION Otherwise, the syntax is the same For example: ALTER SYSTEM SET USE_STORED_OUTLINES =GENERAL_LEDGER NOOVERRIDE; In this case, all existing OUTLINES can continue to be used with the GENERAL_LEDGER outlines that are now used as well If NOOVERRIDE was not specified, the GENERAL_LEDGER outlines will replace those currently being used Likewise, to disable outlines system-wide: ALTER SYSTEM SET USE_STORED_OUTLINES= FALSE; 1.9.3 Managing Outlines You can view outlines to verify that they have been recording correctly and to see what execution plan has been recorded You can also transfer outlines from one schema to another 1.9.3.1 Viewing your outlines To view outlines in order to test whether they are recording, select from the OUTLN.OL$ and OUTLN.OL$HINTS tables OUTLN.OL$ contains the SQL statements, and OUTLN.OL$HINTS contains the optimizer hints to use with the statements In addition to the tables owned by the OUTLN user, you can also view your own personal outlines by querying the USER_OUTLINES and USER_OUTLINE_HINTS views (also see the DBA_ and ALL_ views) For example: SELECT uo.name, sql_text , hint FROM user_outlines uo, user_outline_hints uoh WHERE uo.name = uoh.name ORDER BY join_pos SYS_OUTLINE_010805222913599 select owner ||','|| first ||','|| second ||',' ||third ||',' ||points from winners_current_month where points > and owner is not null order by points desc NO_FACT(WINNERS_CURRENT_MONTH) To observe if an outline is currently being used for SQL statements, you can look in the OUTLINE_CATEGORY column of the V$SQL table for the row containing the SQL statement you are interested in 1.9.3.2 Transferring outlines between databases Transferring outlines across databases is simply a case of export and import For example: EXP OUTLN/OUTLN FILE=OUTLN_21SEP2001.DMP TABLES=OL$, OL$HINTS BUFFER=262144 IMP OUTLN/OUTLN FILE=OUTLN_21SEP2001.DMP BUFFER=262144 IGNORE=Y This example transfers outlines for all schemas After the import, you can delete rows from the OL$ and OL$HINTS tables in the target database for schemas that you don't wish to transfer 1.9.3.3 Dealing with literals Many applications use literals instead of bind variables This means that SQL statements will often be similar, and should use the same execution plan However, since there is one value, the literal value, different from one statement to the next, that sharing of execution plans does not happen Unfortunately, Oracle does not assist us here, even with CURSOR_SHARING = FORCE or SIMILAR Cursor sharing does not work for outlines I am sure that Oracle will address this issue in the future ... a quick-reference guide for tuning Oracle SQL This is not a comprehensive Oracle tuning book The purpose of this book is to give you some light reading material on my "real world" tuning experiences... cost-based optimizer Here is a list of the reasons why: • The time spent coding is reduced • Coders not need to be aware of the rules • There are more features, and far more tuning tools, available... in an index are specified in the WHERE clause, that index will be used in preference to other indexes for which some columns are referenced For example: SELECT col1, FROM emp WHERE emp_name =

Ngày đăng: 26/03/2019, 11:35