Zicklin School of Business - Baruch College
City Unversity of New York

Database Management Systems II
Query Optimization Example


Query Optimization Example

The following notes cover some basic examples of query optimization and hints in Oracle. These examples assuem you have an Oracle account at Baruch College. If you do not, the following instructions may be much different for your local installation.

Database Schema

The following example of an OLTP system resides in the the WAREHOUSE schema of the Oracle database. The data model consists of a normalized schema including tables for BRANCH, CLIENT, POWER, RENTAL, STAFF and VIEWING.

For a list of the CREATE TABLE and other DDL statements used to create the schema Check here. You will also see a list of the indexes as well. Note that you do not have to create this schema - it has already been done in the Oracle database at Baruch College.

Step 1: Create the PLAN_TABLE table in your schema

Copy and paste the following CREATE TABLE statement into your Oracle schema using SQL*Plus. You need only do this ONE TIME.

CREATE TABLE PLAN_TABLE ( STATEMENT_ID VARCHAR2(30), TIMESTAMP DATE, REMARKS VARCHAR2(80), OPERATION VARCHAR2(30), OPTIONS VARCHAR2(30), OBJECT_NODE VARCHAR2(128), OBJECT_OWNER VARCHAR2(30), OBJECT_NAME VARCHAR2(30), OBJECT_INSTANCE NUMERIC, OBJECT_TYPE VARCHAR2(30), OPTIMIZER VARCHAR2(255), SEARCH_COLUMNS NUMBER, ID NUMERIC, PARENT_ID NUMERIC, POSITION NUMERIC, COST NUMERIC, CARDINALITY NUMERIC, BYTES NUMERIC, OTHER_TAG VARCHAR2(255), PARTITION_START VARCHAR2(255), PARTITION_STOP VARCHAR2(255), PARTITION_ID NUMERIC, OTHER LONG, DISTRIBUTION VARCHAR2(30));

The PLAN_TABLE is used to store data about your query plan.

Step 2: Format some columns so that query results print nicely

Each time you log into SQL*Plus and you want to try these exercises, paste in these COLUMN ... FORMAT commands so that the output is formatted nicely. Note that these commands do not affect the underlying data types or data. They only affect how the query results are formatted in SQL*Plus.

COLUMN propertyno FORMAT A10 COLUMN city FORMAT A10 COLUMN staffno FORMAT A6 COLUMN lname FORMAT A10 COLUMN branchno FORMAT A6

Step 3: Turn on the AUTOTRACE facility in SQL*Plus

Step 4: Run a query

The following query runs against tables in the WAREHOUSE schema. In the FROM clause, the WAREHOUSE schema has been specified. This is where the tables are stored.

SELECT rental.propertyNo, rental.city, rental.staffNo, staff.lName, staff.branchNo, branch.city FROM warehouse.rental, warehouse.staff, warehouse.branch WHERE rental.staffNo = staff.staffNo AND staff.branchNo = branch.branchNo AND branch.city = rental.city AND rental.rooms > 3 AND (staff.salary > 10000 OR rental.rtype = 'House')

Here is the output from running this command with the AUTOTRACE facility on:
SQL> COLUMN propertyno FORMAT A10 SQL> COLUMN city FORMAT A10 SQL> COLUMN staffno FORMAT A6 SQL> COLUMN lname FORMAT A10 SQL> COLUMN branchno FORMAT A6 SQL> SET AUTOTRACE ON SQL> SELECT rental.propertyNo, rental.city, rental.staffNo, 2 staff.lName, staff.branchNo, branch.city 3 FROM warehouse.rental, warehouse.staff, warehouse.branch 4 WHERE rental.staffNo = staff.staffNo 5 AND staff.branchNo = branch.branchNo 6 AND branch.city = rental.city 7 AND rental.rooms > 3 8 AND (staff.salary > 10000 9 OR rental.rtype = 'House') ; PROPERTYNO CITY STAFFN LNAME BRANCH CITY ---------- ---------- ------ ---------- ------ ---------- PG16 Glasgow SG14 Ford B003 Glasgow PG21 Glasgow SG37 Beech B003 Glasgow PA14 Aberdeen SA9 Howe B007 Aberdeen Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 NESTED LOOPS 2 1 NESTED LOOPS 3 2 TABLE ACCESS (FULL) OF 'BRANCH' 4 2 TABLE ACCESS (BY INDEX ROWID) OF 'RENTAL' 5 4 INDEX (RANGE SCAN) OF 'IDX_RENTAL_CITY' (NON-UNIQUE) 6 1 TABLE ACCESS (BY INDEX ROWID) OF 'STAFF' 7 6 INDEX (UNIQUE SCAN) OF 'PK_STAFF' (UNIQUE) Statistics ---------------------------------------------------------- 0 recursive calls 4 db block gets 23 consistent gets 0 physical reads 0 redo size 646 bytes sent via SQL*Net to client 359 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 3 rows processed

Step 5: Adding Query Hints

As an exercise, try different query hints such as RULE, CHOOSE, ORDERED, FIRST_ROWS, ALL_ROWS, FULL, INDEX and so on for the above query. Then use the AUTOTRACE feature to see which would be the lowest cost way (in terms of db block gets, consistent gets and physical reads) to run the query (be sure you have created the PLAN_TABLE table and you have SET AUTOTRACE ON).

SELECT /*+ALL_ROWS */ rental.propertyNo, rental.city, rental.staffNo, staff.lName, staff.branchNo, branch.city FROM warehouse.rental, warehouse.staff, warehouse.branch WHERE rental.staffNo = staff.staffNo AND staff.branchNo = branch.branchNo AND branch.city = rental.city AND rental.rooms > 3 AND (staff.salary > 10000 OR rental.rtype = 'House'); PROPERTYNO CITY STAFFN LNAME BRANCH CITY ---------- ---------- ------ ---------- ------ ---------- PG16 Glasgow SG14 Ford B003 Glasgow PG21 Glasgow SG37 Beech B003 Glasgow PA14 Aberdeen SA9 Howe B007 Aberdeen Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=4 Card=1 Bytes=269) 1 0 NESTED LOOPS (Cost=4 Card=1 Bytes=269) 2 1 HASH JOIN (Cost=3 Card=1 Bytes=215) 3 2 TABLE ACCESS (FULL) OF 'RENTAL' (Cost=1 Card=5 Bytes=605) 4 2 TABLE ACCESS (FULL) OF 'STAFF' (Cost=1 Card=82 Bytes=7708) 5 1 TABLE ACCESS (BY INDEX ROWID) OF 'BRANCH' (Cost=1 Card=82 Bytes=4428) 6 5 INDEX (UNIQUE SCAN) OF 'PK_BRANCH' (UNIQUE) Statistics ---------------------------------------------------------- 222 recursive calls 8 db block gets 20 consistent gets 0 physical reads 0 redo size 646 bytes sent via SQL*Net to client 359 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 9 sorts (memory) 0 sorts (disk) 3 rows processed

Below is another example using the RULE based optimizer.

SELECT /*+RULE */ rental.propertyNo, rental.city, rental.staffNo, staff.lName, staff.branchNo, branch.city FROM warehouse.rental, warehouse.staff, warehouse.branch WHERE rental.staffNo = staff.staffNo AND staff.branchNo = branch.branchNo AND branch.city = rental.city AND rental.rooms > 3 AND (staff.salary > 10000 OR rental.rtype = 'House'); PROPERTYNO CITY STAFFN LNAME BRANCH CITY ---------- ---------- ------ ---------- ------ ---------- PG16 Glasgow SG14 Ford B003 Glasgow PG21 Glasgow SG37 Beech B003 Glasgow PA14 Aberdeen SA9 Howe B007 Aberdeen Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=HINT: RULE 1 0 NESTED LOOPS 2 1 NESTED LOOPS 3 2 TABLE ACCESS (FULL) OF 'BRANCH' 4 2 TABLE ACCESS (BY INDEX ROWID) OF 'RENTAL' 5 4 INDEX (RANGE SCAN) OF 'IDX_RENTAL_CITY' (NON-UNIQUE) 6 1 TABLE ACCESS (BY INDEX ROWID) OF 'STAFF' 7 6 INDEX (UNIQUE SCAN) OF 'PK_STAFF' (UNIQUE) Statistics ---------------------------------------------------------- 0 recursive calls 4 db block gets 23 consistent gets 0 physical reads 0 redo size 646 bytes sent via SQL*Net to client 359 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 3 rows processed

More about Oracle's Query Optimizers


File: optimizationex.html Date: Wed Oct 24 12:40:31 EDT 2001
All materials Copyright, 1997-2001 Richard Holowczak