12.5 Reporting on SQL Execution PlansIf you've been a DBA for more than 15 nanoseconds, you've no doubt received an urgent phone call that goes something like this:
The next sentence is almost always: "It worked fine, last week!" As you try desperately to determine why this critical piece of SQL is suddenly running slower than a three-toed sloth taking a nap, you may think to yourself:
We've had that exact same thought any number of times ourselves. And so the SXP portion of the PDBA repository was born. 12.5.1 SXP (SQL EXecution Plan) Scripts and TablesThe scripts and tables that make up SXP come in threes — we've designed a triumvirate of tables described earlier in this chapter in Table 12-2 (and shown graphically in Figure 12-1) used to store SQL and its corresponding execution plans, and we've designed a triumvirate of Perl scripts that populate these tables and report on the results. The scripts are:
Figure 12-1. The SPX table system12.5.2 SXP LimitationsHelpful as the SXP scripts are, they do have a few limitations:
12.5.3 Collecting SQL with sxp.plWith those caveats out of the way, let's go about the business of actually using this utility. You'll use the sxp.pl script to collect SQL from the database and store it in the repository. On our test database, this script runs in less than a minute. We also employ this tool on several production databases where it can take several minutes[5] to complete.
You can enter the following command to collect SQL from database ts01 on server sherlock. (Coincidentally, this is the same database on which the repository resides.) Table 12-7 lists the command-line options for this script. $ sxp.pl -machine sherlock -database ts01 -username system \ -rep_machine sherlock -rep_database ts01 \ -rep_username pdbarep
12.5.3.1 Unique constraint errorExample 12-13 contains the actual output from sxp.pl, as it was run on one of our test databases. You'll notice that there is an Oracle error: ORA-00001: unique constraint (PDBAREP.PDBA_SXP_UK_IDX) violated This error occurred about halfway through processing. This happens occasionally when there are syntactically identical SQL statements in the database cache that have been formatted somewhat differently. When sxp.pl encounters these paired statements, they're reformatted identically for our EXPLAIN PLAN statement. That results in sxp.pl trying to save the same SQL statement twice during the same session. This was a design decision on our part. Rather than search the PDBA_SXP_SQL table looking for duplicates each time we save SQL to the repository, we simply let the database catch it with a unique constraint. The sxp.pl script traps this error, reports it, and continues onto the next SQL statement. Example 12-13. Output from sxp.pl%oramon> sxp.pl -machine sherlock -database ts01 -username system \ -rep_machine sherlock -rep_database ts01 -rep_username pdbarep .......DBD::Oracle::st execute failed: ORA-00001: unique constraint (PDBAREP.PDBA_SXP_SQL_UK_IDX) violated (DBD ERROR: OCIStmtExecute) at /usr/local/bin/sxp.pl line 283 ...no password available from PWD for ORADES ....%oramon> 12.5.3.2 Password and privilege messagesYou'll note another message in the sxp.pl output, but this one is simply informational: no password available from PWD for ORADES This means that there are SQL statements within the cache for the user ORADES, but that their password was not available from the password server, and thus processing moved onto the next user. Another error that may appear is: ORA-01039: insufficient privileges on underlying objects of the view We encounter this error when attempts are made to generate execution plans for a SELECT statement on a view. Although the user may have SELECT privileges on the view, Oracle requires that we also have SELECT privileges on the view's underlying tables in order to generate an execution plan. There is nothing we can do about that, so we report the error and move onto the next SQL statement. 12.5.4 Reporting Execution PlansThe sxprpt.pl script reports on the SQL and execution plans now stored within the PDBA repository. Table 12-8 lists the command-line options for this script.
Now that we have some data loaded into the repository, let's get a report of what's in there. Because our test database already contains a number of data collections, we'll limit the report by specifying a date range constraint in the following command: $ sxprpt.pl -machine sherlock -database ts01 \ -username pdbarep -rpt_database 'ts01%' \ -rpt_start_date '11/25/2001' -rpt_end_date '11/27/2001' The resulting report will contain the following:
If all goes well, there will be:
In the event that an error occurs while generating the execution plan, the error will be displayed instead of the execution plan. 12.5.5 ChecksumsThis might be a good time to explain the way checksums work within our scripts. Whenever a SQL statement or execution plan is stored in the repository, the Perl security module Digest::MD5 is drafted into action to generate a unique 32-character "message digest" of the data. Because this digest will be unique for each SQL statement and execution plan, it serves as a unique key that we can use to search for identical SQL statements and compare execution plans. Using a checksum results in better performance — much smaller indexes and faster search times. 12.5.6 Example SPX ReportFor your edification and delight, we've reproduced a portion of an SPX report from one of our test databases. In Example 12-14 you'll note that the first SQL statement failed to parse because of Oracle error ORA-00936. This error was the result of the SQL formatting problem mentioned earlier. (This is not a very common error, but worth being aware of.) The second SQL statement in Example 12-14 also failed during the generation of the execution plan. This was because the user had insufficient privileges on a view's underlying objects. In this case, the PDBAREP user has the SELECT privilege granted on the system view ALL_TABLES, but lacks privileges on the data dictionary tables used in that particular view. The third and fourth SQL statements shown in Example 12-14 were both successfully submitted to the Oracle parser for the generation of execution plans via the EXPLAIN PLAN statement. Example 12-14. Example report — sxprpt.plInstance: TS01.JKS.COM sqlUsername: PDBAREP SQL Check Sum: 3413C8988F25F181D463272348F404D4 SnapShot Date: 11/27/2001 12:57:01 SQL Text: SELECT TO_CHAR(SYSDATE ,'MM/DD/YY') TODAY , TO_CHAR(SYSDATE ,'HH:MI AM') TIME , --DATABASE||' Database' DATABASE , --rtrim(database) passout name||' Database' DATABASE , lower(rtrim(name)) passout FROM v$database Explain Check Sum: Explain Plan: Explain Error: ORA-00936: missing expression (DBD ERROR: OCIStmtExecute) at ./sxp.pl line 345. eval {...} called at ========================================================================== sqlUsername: PDBAREP SQL Check Sum: 3A0D45C0E2E730555B413F17A7E41E95 SnapShot Date: 11/25/2001 12:56:24 SQL Text: SELECT Table_Name FROM ALL_TABLES WHERE OWNER = :f1 ORDER BY Table_Name Explain Check Sum: Explain Plan: Explain Error: ORA-01039: insufficient privileges on underlying objects of the view (DBD ERROR: OCIStmtExecute) at ========================================================================== Instance: TS01.JKS.COM sqlUsername: PDBAREP SQL Check Sum: 07BF585D872E136C7341FF573CAD8FCD SnapShot Date: 11/27/2001 12:57:01 SQL Text: select s.global_name cinstance , t.owner , t.table_name , t.column_name , t.column_id , t.data_type , t.data_length , t.data_precision , t.data_scale , t.nullable from pdba_snap_dates s , pdba_tab_columns t where s.global_name like '%' and t.owner like '%' and t.table_name like '%' -- here is how to get a range of dates and s.pk = 1009436 and s.pk = t.snap_date_pk minus select s.global_name cinstance , t.owner , t.table_name , t.column_name , t.column_id , t.data_type , t.data_length , t.data_precision , t.data_scale , t.nullable from pdba_snap_dates s , pdba_tab_columns t where s.global_name like '%' and t.owner like '%' and t.table_name like '%' -- here is how to get a range of dates and s.pk = 1000000 and s.pk = t.snap_date_pk order by 1,2,3,4 Explain Check Sum: 3D9734F45B31736AB7DF5B69FB8DA713 Explain Plan: TOTAL POS OPERATION OBJECT_NAME COST ROWS BYTES OPTIMIZER -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 29 SELECT STATEMENT 29 5K 294203 CHOOSE 1 MERGE JOIN 29 5K 294203 1 TABLE ACCESS FULL PDBA_SNAP_DATES 1 7 84 ANALYZED 2 SORT JOIN 28 793 32513 1 TABLE ACCESS FULL PDBA_TAB_COLUMNS 4 793 32513 ANALYZED Explain Error: ========================================================================== Instance: TS01.JKS.COM sqlUsername: PDBAREP SQL Check Sum: 3BE4FE5486D11246DA2A358A27A0CE92 SnapShot Date: 11/27/2001 12:57:01 SQL Text: select * from PDBA_SNAP_DATES where snap_date < trunc(to_date('01/01/1700' ,'mm/dd/yyyy')+1) order by snap_date Explain Check Sum: 2C7545806582F6D3EC95AA2F48212C6D Explain Plan: TOTAL POS OPERATION OBJECT_NAME COST ROWS BYTES OPTIMIZER -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 2 SELECT STATEMENT 2 1 24 CHOOSE 1 TABLE ACCESS ROWID PDBA_SNAP_DATES 2 1 24 ANALYZED 1 INDEX RANGE SCAN PDBA_SNAP_DATES_UK_IDX 1 1 0 ANALYZED Explain Error: 12.5.6.1 Comparing execution plansNow let's take a look at the sxpcmp.pl script. This script scans the SQL buffer via the V_$SQLTEXT view and prepares execution plans and SQL checksums in the buffer. Next, it searches the PDBA repository for a SQL statement with a matching checksum. If more than one match is found in the repository, the most recent one is used. This behavior may be modified with the -rep_report_date option. (See Table 12-9 for all of the command-line options.) If a matching SQL statement is found, the script compares the checksums for the current execution plan and the stored execution plan. If these match, nothing is reported and the next SQL statement is checked. If the checksums for the execution plans don't match, this indicates that some database change has taken place, thus altering the way the SQL executes. The SQL and both execution plans are reported.
Example 12-15 contains a sample report generated from sxpcmp.pl. The command used to generate this report looks like this: $ sxpcmp.pl -machine sherlock -database ts01 \ -username system -rep_machine sherlock \ -rep_database ts01 -rep_username pdbarep \ -rep_report_date '12/15/2001' > sxpcmp.txt 12.5.6.2 Looking at the outputIt's a good idea to redirect the output of sxpcmp.pl to a file, as we've done via this command, because a fair number of pop-up warnings may end up cluttering the screen on a run through a complex database. Typically, all of the warnings are sent to STDERR, so redirecting STDOUT to a file will often provide a cleaner report. Example 12-15. Output from sxpcmp.plActive SQL From Data Dictionary Matching SQL In Repository Page: 1 But With Different Execution Paths Database: TS01.JKS.COM Date: 12/16/2001 ========================================================================== SQL Username: SCOTT SQL Check Sum: 75125F4AD88511A11D3C12AF83BE8F4C SnapShot Date: 12/15/2001 14:27:57 SQL Text: select /*+ index(e emp_deptno) */ * from dept d , emp e where d.deptno = e.deptno Current Explain Plan: TOTAL POS OPERATION OBJECT_NAME COST ROWS BYTES OPTIMIZER -------------------------------------------------------------------- 4 SELECT STATEMENT 4 14 700 CHOOSE 1 HASH JOIN 4 14 700 1 TABLE ACCESS BY INDEX EMP 2 14 448 ANALYZED 1 INDEX FULL SCAN EMP_DEPTNO 1 14 0 ANALYZED 2 TABLE ACCESS FULL DEPT 1 4 72 ANALYZED Stored Explain Plan: TOTAL POS OPERATION OBJECT_NAME COST ROWS BYTES OPTIMIZER -------------------------------------------------------------------- 3 SELECT STATEMENT 3 14 700 CHOOSE 1 HASH JOIN 3 14 700 1 TABLE ACCESS FULL DEPT 1 4 72 ANALYZED 2 TABLE ACCESS FULL EMP 1 14 448 ANALYZED Note the following about this output:
|