Informix Performance Optimization
Table of Contents
Author: Kevin Fennimore
Informix Performance Optimization Overview: Steps for Optimizing Optimization Goal: Increase Performance Setting up a Test Environment Optimizing the Query: Understand the Requirements Optimizing the Query: Examine the Schema Optimizing the Query: Examine the Data Optimizing the Query: Run, Examine and Modify Set Explain Output Set Explain: Example 1 Set Explain: Example 2 Set Explain: Example 3 Set Explain: Example 4 Set Explain: Example 5 Set Explain: Example 6 Set Explain: Example 7 Set Explain: Example 8 Set Explain: Example 8 cont. Indexing Strategies Indexing Strategies: B+ Trees Indexing Strategies: Types of Indexes Indexing Strategies: Leading Portion of an Index Indexing Strategies: Guidelines Indexing Strategies: Benefits vs. Cost
Email: [email protected]
by
Kevin Fennimore
Overview:
Discuss steps for optimizing Discuss the output of the Set Explain command
Discuss Indexing Strategies New SQL in OnLine Dynamic Server (IDS 7.3) Table Scans & Table Joins Optimizer Directives (IDS 7.3) Discuss optimization techniques and examples XTREE command Correlated Sub-Queries (IDS 7.3)
Steps for Optimizing Optimization Goal: Increase Performance
Reduce I/O
o o
reduce I/O performed by the engine reduce I/O between the back-end and the front-end
Reduce processing time
Setting up a Test Environment
Identify Problem Queries Simplify Queries Test on a machine with minimal system activity
Use database that reflects production data Turn Set Explain on
Optimizing the Query: Understand the Requirements
What is the object of the query? What is the information required? What is the order criteria?
Optimizing the Query: Examine the Schema
Identify the the data types and indexes on the columns being:
o o o o
selected used as filters used in joins used for sorting
Be aware of constraints on the data( e.g. primary, check, etc. )
Optimizing the Query: Examine the Data
Consider the number of rows examined vs. the number of rows returned
Determine the distribution of filter columns Look at the relationship of joined tables:
o o o
one-to-one one-to-many many-to-many
Optimizing the Query: Run, Examine and Modify
Run the Query:
query.sql $ timex dbaccess db query.sql > try1.out 2>&1
Examine the Set Explain output Modify the query and/or schema (use directives to test various paths) Run the query again
Set Explain Output Set Explain: Example 1
QUERY: select * from stock order by description Estimated Cost: 6
Estimated # of Rows Returned: 15 Temporary Files Required For: Order By 1) informix.stock: SEQUENTIAL SCAN
Set Explain: Example 2
QUERY: select * from stock where unit_price order by stock_num Estimated Cost: 3 Estimated # of Rows Returned: 5 1) informix.stock: INDEX PATH Filters: informix.stock.unit_price > 20 (1) Index Keys: stock_num manu_code
Set Explain: Example 3
QUERY: select manu_code from stock Estimated Cost: 2 Estimated # of Rows Returned: 15
1) informix.stock: INDEX PATH (1) Index Keys: stock_num manu_code (Key-Only)
Set Explain: Example 4
QUERY: select * from stock where stock_num and stock_num Estimated Cost: 1 Estimated # of Rows Returned: 1 1) informix.stock: INDEX PATH (1) Index Keys: stock_num manu_code Lower Index Filter: informix.stock.stock_num > 10 Upper Index Filter: informix.stock.stock_num < 14
Set Explain: Example 5
QUERY: select * from stock, items where stock.stock_num = items.stock_num and items.quantity
Estimated Cost: 9 Estimated # of Rows Returned: 22 1) informix.stock: SEQUENTIAL SCAN 2) informix.items: INDEX PATH Filters: informix.items.quantity > 1 (1) Index Keys: stock_num manu_code Lower Index Filter: informix.items.stock_num = informix.stock.stock_num
Set Explain: Example 6
QUERY: select * from items,stock where items.total_price=stock.unit_price Estimated Cost: 19 Estimated # of Rows Returned: 59 1) informix.items: SEQUENTIAL SCAN SORT SCAN: informix.items.total_price 2) informix.stock: SEQUENTIAL SCAN SORT SCAN: informix.stock.unit_price
MERGE JOIN Merge Filters: informix.stock.unit_price = informix.items.total_price
Prior to version 5.0 this would have caused an auto-index on the second table.
Set Explain: Example 7
QUERY: -----select * from items, stock where items.total_price = stock.unit_price Estimated Cost: 35 Estimated # of Rows Returned: 496 1) informix.items: SEQUENTIAL SCAN 2) informix.stock: SEQUENTIAL SCAN DYNAMIC HASH JOIN Dynamic Hash Filters: informix.items.total_price = informix.stock.unit_price
Set Explain: Example 8
Table ps_ledger has the following index: create index psaledger on ps_ledger ( account, fiscal_year, accounting_period, business_unit, ledger, currency_cd, statistics_code, deptid, product, posted_total_amt ) fragment by expression ( fiscal_year = 1999 ) in dbspace1, ( fiscal_year = 2000 ) in dbspace1, remainder in dbspace1
Set Explain: Example 8 cont.
QUERY: -----select fiscal_year, account, posted_total_amt from ps_ledger where fiscal_year = 1999 and accounting_period = 10 and account between '1234' and '9999' 1) sysadm.ps_ledger: INDEX PATH Filters: (ps_ledger.fiscal_year = 1999 AND ps_ledger.accounting_period = 10 ) (1) Index Keys: account fiscal_year accounting_period business_unit ledger currency_cd statistics_code deptid product posted_total_amt (Key-Only) (Serial, fragments: 0) Lower Index Filter: ps_ledger.account >= '1234' Upper Index Filter: ps_ledger.account <= '9999'
Indexing Strategies Indexing Strategies: B+ Trees Indexing Strategies: Types of Indexes
Unique Duplicate Composite Clustered Attached Detached
Indexing Strategies: Leading Portion of an Index
Consider an index on columns a, b and c on table xyz.
Index is used for: SELECT * FROM XYZ WHERE a = 1 AND b = 2 AND c = 3 SELECT * FROM XYZ WHERE a = 1 AND b = 2 SELECT * FROM XYZ
WHERE a = 1 ORDER BY a, b, c Index is not used for: SELECT * FROM XYZ WHERE b = 2 AND c = 3 SELECT * FROM XYZ WHERE b = 2 SELECT * FROM XYZ WHERE c = 3 ORDER BY b, c
Indexing Strategies: Guidelines
Columns used in joining tables Columns used as filters Columns used in ORDER BYs and GROUP BYs Avoid highly duplicate columns Keep key size small Limit indexes on highly volatile tables Use the FILL FACTOR option (version 7)
Indexing Strategies: Benefits vs. Cost
Benefits Guarantee Uniqueness Speed up Queries
Cost Maintenance of indexes on Inserts, Updates & Deletes Extra Disk Space
New SQL for Informix Dynamic Server 7.3 New SQL in IDS 7.3
Select first N rows Directives String Manipulation
o o
UPPPER, lower, InitCap replace, substr, lpad, rpad
CASE, NVL, DECODE TO_CHAR, TO_DATE DBINFO Views with UNIONs
New SQL in IDS 7.3: First N rows
SELECT FIRST 10 * from customer where state = MD
order by any_column;
This causes the first 10 rows from the result set to be returned.
New SQL in IDS 7.3: CASE
SELECT name, case when status = A then Active when status = I then Inactive else Invalid Status end, state from customer order by name
SELECT name, case status when A then Active when I then Inactive else Invalid Status end, state
from customer order by name OR
New SQL in IDS 7.3: DECODE
SELECT name, DECODE( status, A, Active, I, Inactive, Invalid Status ), state from customer order by name
New SQL in IDS 7.3: NVL
SELECT name, address1, NVL( address2, ), NVL( status, No status ), city, state, zipcode from customer
order by name
This could also be: CASE WHEN address2 is NULL then else address2
New SQL in IDS 7.3: DBINFO
SELECT DBINFO ( DBSPACE, partnum ), tabid, tabname from systables order by 1
Table Scans Types of Table Scans
Sequential Auto Index Index
Index Scans: Upper and Lower Index Filters
QUERY: select * from stock where stock_num>=99 and stock_num<=190 Estimated Cost: 1 Estimated # of Rows Returned: 1 1) informix.stock: INDEX PATH (1) Index Keys: stock_num manu_code Lower Index Filter: informix.stock.stock_num >= 99 Upper Index Filter: informix.stock.stock_num <= 190
Index Scans: Upper and Lower Index Filters Index Scans: Upper and Lower Index Filters
Create indexes on columns that are the most selective. For example: SELECT * FROM CUSTOMER WHERE ACCOUNT BETWEEN 100 and 1000 AND STATUS = A AND STATE = MD
Which column is the most selective? Account, status or state?
Index Scans: Key-Only
QUERY: select manu_code from stock where stock_num = 190 Estimated Cost: 2 Estimated # of Rows Returned: 15 1) informix.stock: INDEX PATH (1) Index Keys: stock_num manu_code (Key-Only) Lower Index Filter: informix.stock.stock_num = 190
Index Scans: Key-First
QUERY: select count(e)from mytable where a=1 and b=1 and d="Y"
Estimated Cost: 4 Estimated # of Rows Returned: 1 1) informix.mytable: INDEX PATH Filters: informix.mytable.d = 'Y' (1) Index Keys: a b c d (Key-First) (Serial, fragments: ALL) Lower Index Filter: (informix.mytable.a = 1 AND informix.mytable.b = 1 )
Table Joins Joining Tables
Consider the following query:
select * from stock, items where stock.stock_num = items.stock_num and items.quantity
What were looking for is:
All of the items records with a quantity greater than 10 and their associated stock records.
Joining Tables: Join Methods
Sort Merge Join Dynamic Hash Join Nested Loop Join
Join Methods: Nested Loop Join
QUERY: select * from stock, items where stock.stock_num = items.stock_num and items.quantity Estimated Cost: 9 Estimated # of Rows Returned: 22 1) informix.stock: SEQUENTIAL SCAN 2) informix.items: INDEX PATH Filters: informix.items.quantity > 10 (1) Index Keys: stock_num manu_code Lower Index Filter:items.stock_num = stock.stock_num NESTED LOOP JOIN
Notice the index on the joined column New Output in version 7.3
Joining Tables: Table Order
Consider the select:
Select * from A, B where A.join_col = B.join_col
How can the database satisfy this join?
o o
Read from A then find matching rows in B Read from B then find matching rows in A
Joining Tables: Table Order Who Cares?
A then B 1,000 reads from A For each A row do an index scan into B (4 reads) Total reads: 5,000 (1,000 for A + 1,000*4 for B) B then A 50,000 reads from B For each B row do an index
scan into A (3 reads) Total reads: 200,000 (50,000 for B + 50,000*3 for A)
Table A - 1000 rows Table B - 50,000 rows This is a difference of 195,000 reads!!!
Joining Tables: Table Order What is the best order?
A then B 1,000 reads from A For each A row do an index scan into B (4 reads) Total reads: 5,000 (1,000 for A + 1,000*4 for B) Total Rows Returned: 10 B then A Index scan of B (3 reads), then the data (10 reads) for a toal of 13 For each B row do an index
scan into A (3 reads) Total reads: 43 (13 for B+10*3 for A) Total Rows Returned: 10
Table A - 1,000 rows Table B - 50,000 rows Select * from A, B where A.join_col = B.join_col and B.filter_col = 1 General Rule: The table which returns the fewest rows, either through a filter or the row count, should be first. Assume 10 rows in B meet this condition
Joining Tables: Table Order What affects the join order?
Number of rows in the tables Indexes available for:
o o
Filters Join Columns
Data Distribution UPDATE STATISTICS is very important
Optimizer Directives
Optimizer Directives
Changes the generated query plan by removing paths from consideration Similar to Oracles HINTs Better than HINTs
o o o o
More options Cannot be ignored Negative directives Set Explain output
Optimizer Directives
A then B Seq A, Seq B Cost:100 Seq A, Idx B Cost:50 Idx A, Idx B Cost:20 etc. B then A Seq B, Seq A Cost:100 Seq B, Idx A Cost:50 Idx B, Idx A Cost:10 etc.
Select --ORDERED * from A, B where A.join_col = B.join_col With the directive, ORDERED, the optimizer only considers paths that read from A then B. The lowest cost is then chosen from those paths. Normally, this path would be chosen With the directive, this path would be chosen
Optimizer Directives: Syntax
SELECT --+ directive text SELECT {+ directive text } UPDATE --+ directive text UPDATE {+ directive text } DELETE --+ directive text DELETE {+ directive text }
C-style comments are also valid as in: SELECT /*+directive*/
Types of Directives
Access Methods Join Methods Join Order
Optimization Goal
Types of Directives: Access Methods
index - forces use of a subset of specified indexes index_one - forces use of one of the specified indexes index_all - forces use of all of the specified indexes avoid_index - avoids use of specified indexes full - forces sequential scan of specified table avoid_full - avoids sequential scan of specified table
Types of Directives: Join Order
ordered - forces table order to follow the from clause
Types of Directives: Optimization Goal
first_rows (N) - tells the optimizer to choose a plan optimized to return the first N rows of the result set all_rows - tells the optimizer to choose a plan optimized to all tupelos
Types of Directives: Join Methods
use_nl - forces nested loop join on specified tables use_merge - forces sort merge join on specified tables use_hash - forces hash join on specified tables avoid_nl - avoids nested loop join on specified tables avoid_merge - avoids sort merge join on specified tables avoid_hash - avoids hash join on specified tables
Directives Examples: ORDERED
QUERY: select --+ ordered customer.lname, orders.order_num, items.total_price from customer, orders, items where customer.customer_num = orders.customer_num and orders.order_num = items.order_num and items.stock_num = 6 and items.manu_code = "SMT" DIRECTIVES FOLLOWED: ORDERED
DIRECTIVES NOT FOLLOWED: 1) customer: SEQUENTIAL SCAN 2) orders: INDEX PATH (1) Index Keys: customer_num Lower Index Filter: orders.customer_num = customer.customer_num NESTED LOOP JOIN 3) items: INDEX PATH Filters: items.order_num = orders.order_num (1) Index Keys: stock_num manu_code Lower Index Filter: (items.stock_num = 6 AND items.manu_code = 'SMT' ) NESTED LOOP JOIN
Directives Examples : INDEX
QUERY: -----select --+ ordered index(customer, zip_ix) avoid_index(orders," 101_4")
customer.lname, orders.order_num, items.total_price from customer c, orders o, items i where c.customer_num = o.customer_num and o.order_num = i.order_num and stock_num = 6 and manu_code = "SMT"
Directives Examples : INDEX (cont.)
DIRECTIVES FOLLOWED: ORDERED INDEX ( customer zip_ix ) AVOID_INDEX ( orders 101_4 ) DIRECTIVES NOT FOLLOWED: 1)customer: INDEX PATH (1) Index Keys: zipcode 2)orders: SEQUENTIAL SCAN DYNAMIC HASH JOIN (Build Outer) Dynamic Hash Filters:c.customer_num =o.customer_num 3)items: INDEX PATH
Filters:i.order_num =o.order_num (1) Index Keys: stock_num manu_code Lower Index Filter: (i.stock_num = 6 AND i.manu_code = 'SMT' ) NESTED LOOP JOIN
Directives Examples : Errors
QUERY: select --+ ordered index(customer, zip_ix) avoid_index(orders," 222_4") customer.lname, orders.order_num, items.total_price from customer, orders, items where customer.customer_num = orders.customer_num and orders.order_num = items.order_num and stock_num = 6 and manu_code = "SMT" DIRECTIVES FOLLOWED: ORDERED INDEX ( customer zip_ix ) DIRECTIVES NOT FOLLOWED:
AVOID_INDEX( orders 222_4 ) Invalid Index Name Specified.
Optimization Techniques Optimization Techniques
Use Composite Indexes Use Index Filters Create indexes for Key-Only scans Perform indexed reads for sorting Use temporary tables Simplify queries by using Unions Avoid sequential scans of large tables
Optimization Techniques (Cont.)
Drop and recreate indexes for large modifications Avoid Correlated Sub-queries (pre IDS 7.3) Select needed columns vs. Select * Use OUTER JOINS
Prepare and Execute statements
Optimization Techniques: Use Composite Indexes
Composite indexes are ones built on more than one column The optimizer uses the leading portions of a composite index for filters, join conditions and sorts A composite index on columns a, b and c will be used for selects involving:
o o o
column a columns a and b columns a, b and c
It will not be used for selects involving only columns b and/or c since those columns are not at the beginning of the index( i.e. the leading portion )
Optimization Techniques: Use Index Filters
Create indexes on columns that are the most selective. For example: SELECT * FROM CUSTOMER WHERE ACCOUNT BETWEEN 100 and 1000 AND STATUS = A
AND STATE = MD Which column is the most selective? Account, status or state?
Optimization Techniques: Use Index Filters
Assume table xyz has an index on begin_idx & end_idx With the following select:
SELECT * FROM xyz WHERE begin_idx >= 99 AND end_idx <= 150
The leading portion of the index, column begin_idx, will be used.
Optimization Techniques: Use Index Filters Optimization Techniques: Use Index Filters
If we can change the query to include an upper bound on begin_idx as follows:
SELECT * FROM xyz WHERE begin_idx >= 99
AND begin_idx <= 150 AND end_idx <= 150
Optimization Techniques: Use Index Filters Optimization Techniques: Key-Only Scans
Data for the select list is read from the index key -- No read of the data page is needed Useful for inner tables of nested-loop joins Useful for creating a sub-table for very wide tables
Optimization Techniques: Indexed Reads for Sorting
Indexed reads cause rows to be read in the order of the indexed columns Higher priority is given to indexes on columns used as filters Reasons why an index will not be used to perform a sort:
o o o
Columns in the sort criteria are not in the index Columns in the sort criteria are in a different order than the index Columns in the sort criteria are from different tables
Optimization Techniques: Indexed Reads for Sorting
select * from some_table where x = ? and y = ? order by z Assume the table some_table has a composite index on columns x, y and z. Note: With Informix Dynamic Server v7.31 this is done automatically by the optimizer. select * from some_table where x = ? and y = ? order by x, y, z
Optimization Techniques: Indexed Reads for Sorting
select a.invt, a.location, a.sku from inv_sum a, loc_master b where a.location = b.location and b.code in ( A, B, C ) order by a.location, a.sku
Table inv_sum has 300,000 records and a composite index on the columns location and sku. Table loc_master has an index on code. There is a 1-to-1 relationship between the tables. The filter condition on code excludes about 20,000 records, leaving 280,000 to be sorted. The optimizer gives preference to the index on the filter column code and a temporary file is used for the sorting instead of doing an indexed read on the composite index.
Optimization Techniques: Indexed Reads for Sorting
select a.invt, a.location, a.sku from inv_sum a, loc_master b where a.location = b.location and a.location >= order by a.location, a.sku
By moving the filter from the select into the program and adding a dummy filter on location, the optimizer chooses to use the composite index for the filter and the sorting. Note: location >= will return all values for location since all character strings are greater than the empty string.
Optimization Techniques: Indexed Reads for Sorting
select --+ INDEX( a i_inv_sum1 ) a.invt, a.location, a.sku from inv_sum a, loc_master b where a.location = b.location and b.code in ( A, B, C ) order by a.location, a.sku
With IDS v7.3, an optimizer directive could be used. Assuming the index name on inv_sum was i_inv_sum1, the select would be: The ORDERED directive might have done the same thing.
Optimization Techniques: Temporary Tables
Useful for batch reporting Avoid selecting a subset of data repetitively from a larger table Create summary information that can be joined to other tables
Disadvantage The data in the temporary table is a copy of the real data and therefore is not changed if the original data is modified.
Optimization Techniques: Temporary Tables
select b.sku, sum(b.sz_qty) tot_qty from ctn a, ctn_detail b where a.carton_stat = "Q" and a.ctn_id = b.ctn_id group by b.sku into temp tmp1 with no log;
create index i1 on tmp1( sku ) select tot_qty from tmp1 where sku = ?
select sum(b.sz_qty) from ctn a, ctn_detail b where a.carton_stat = "Q" and a.ctn_id = b.ctn_id and b.sku = ? The ctn table contains 300,000 records and very few records have a status of Q.
Optimization Techniques: Using UNIONs
OR's can cause the optimizer to not use indexes Complex where conditions can cause the optimizer to use the wrong index Note: Informix Dynamic Server v7.3 allows UNIONs in views
Optimization Techniques: Using UNIONs
select sum(qty) from log where trans_id = 1 and sku = ?
and date_time > ? UNION ... select sum(qty) from log where trans_id = 8 and sku = ? and date_time > ?
select sum(qty) from log where sku = ? and trans_id in ( 1, 2, 3, 4, 5, 6, 7, 8 ) and date_time > ? The log table has an index on date_time and a composite index on trans_id, sku and date_time.
Optimization Techniques: Avoid Sequential Scans and Auto Indexes
Sequential scans of large tables are resource intensive Sequential scans of small tables are not harmful Consider using permanent indexes to avoid sequential scans when possible Create temporary indexes for batch reporting
Replace Auto Indexes with real indexes
Optimization Techniques: Drop and Recreate Indexes
Useful for modifications to > 25% of the rows
o o
Eliminates overhead of maintaining indexes during modification Indexes are recreated more efficiently
Indexes can deteriorate over time
Disadvantage The table must be locked in exclusive mode while the indexes are dropped and recreated.
Optimization Techniques: Avoid Correlated Sub-queries
select c.* from customers c, orders o where c.custid = o.custid and o.ord_date = TODAY
select c.* from customers c where c.custid in ( select custid from orders where ord_date = TODAY ) This is an example of a non-correlated sub-query. The performance of these two should be the same.
Optimization Techniques: Avoid Correlated Sub-queries
select c.* from customers c, orders o where c.custid = o.custid and o.stat = OPEN
select c.* from customers c where exists ( select custid from orders o where o.custid = c.custid and o.stat = OPEN )
Optimization Techniques: Select needed columns vs. Select *
select * from customers
select cust_num, last_name from customers If the table customer had many columns, selecting needed columns is more efficient than selecting all of the columns.
Optimization Techniques: Use Outer Joins
SELECT cnum FROM customer WHERE status = A FOREACH SELECT onum FROM ORDERS o WHERE o.cnum = cnum IF ( STATUS = NOTFOUND ) THEN ... END IF END FOREACH
SELECT cnum, onum FROM customer c OUTER order o WHERE status = A AND c.cnum = o.cnum FOREACH IF ( onum IS NULL ) THEN ... END IF END FOREACH
Optimization Techniques: Use Outer Joins
SELECT cnum, NVL( onum, 0 ) FROM customer c OUTER order o WHERE status = A AND c.cnum = o.cnum FOREACH IF ( onum = 0 ) THEN ... END IF END FOREACH
Optimization Techniques: Prepare and Execute
What happens when a statement is sent to the engine?
o o o o
Syntax Check Permission Check Optimization Statement is executed
Optimization Techniques: Prepare and Execute
FOR x = 1 to 1000 INSERT INTO some_table VALUES ( x, 10 )
END FOR
PREPARE p1 FROM INSERT INTO some_table VALUES ( ?, 10 ) FOR x = 1 to 1000 EXECUTE p1 USING x END FOR
Correlated Sub-Queries Correlated Sub-Queries What are they?
select c.* from customers c, orders o where c.custid = o.custid and o.ord_date = TODAY
select c.* from customers c where c.custid in ( select custid from orders where ord_date = TODAY ) This is an example of a non-correlated sub-query. The performance of these two should be the same.
Correlated Sub-Queries What are they?
select c.*
from customers c, orders o where c.custid = o.custid and o.stat = OPEN
select c.* from customers c where exists ( select X from orders o where o.custid = c.custid and o.stat = OPEN ) select c.* from customers c where custid in ( select custid from orders o where o.stat = OPEN )
Correlated Sub-Queries Whats wrong with them?
Consider the statement:
update customers set stat = A where exists ( select X from orders o where o.custid = customer.custid and o.cmpny = customers.cmpny and o.stat = OPEN )
The statement is executed by executing the sub-query, on orders, for every row retrieved from customers.
If customers table had 100,000 rows, the sub-query would get executed 100,000 times. However, if orders only had 20 rows with stat=OPEN the database would be doing a lot of extra work.
Correlated Sub-queries
update customers set stat = A where exists ( select X from orders o where o.custid = customer.custid and o.cmpny = customers.cmpny and o.stat = OPEN ) and custid in ( select custid from orders o where o.stat = OPEN )
update customers set stat = A where exists ( select X from orders o where o.custid = customers.custid and o.cmpny = customers.cmpny
and o.stat = OPEN ) If orders has only 20 rows meeting the filter, the second version of the update runs much faster, assuming that customers has an index on the column custid. The original CSQ is left since it was joining on more than one column
Correlated Sub-queries: Normal CSQ
QUERY: update orders set ship_charge = 0 where exists ( select "X" from customer c where c.customer_num = orders.customer_num and c.state = "MD ) 1) informix.orders: SEQUENTIAL SCAN Filters: EXISTS <subquery> Subquery: --------Estimated Cost: 1 Estimated # of Rows Returned: 1 1) informix.c: INDEX PATH Filters: informix.c.state = 'MD' (1) Index Keys: customer_num
Lower Index Filter: c.customer_num = orders.customer_num
Correlated Sub-queries: Rewritten CSQ
QUERY: update orders set ship_charge = 0 where customer_num in ( select customer_num from customer c where c.state = "MD ) 1) informix.orders: INDEX PATH (1) Index Keys: customer_num Lower Index Filter:orders.customer_num = ANY <subquery> Subquery: --------1) informix.c: SEQUENTIAL SCAN Filters: informix.c.state = 'MD'
Correlated Sub-queries: CSQ Flattening
QUERY: update orders set ship_charge = 0 where exists ( select "X" from customer c where c.customer_num = orders.customer_num and c.state = "MD ) 1) informix.c: SEQUENTIAL SCAN Filters: informix.c.state = 'MD' 2) informix.orders: INDEX PATH (1) Index Keys: customer_num Lower Index Filter: orders.customer_num = c.customer_num NESTED LOOP JOIN
An index could be created on state to avoid the sequential scan.
Correlated Sub-queries: Predicate Promotion in CSQs
Correlated Version select * from ps_jrnl_ln
where business_unit = 'ABC and process_instance = 5960 and not exists ( select "X" from PS_SP_BU_GL_NONVW P where P.business_unit = ps_jrnl_ln.business_unit ) Non-Correlated Version select * from ps_jrnl_ln where business_unit = 'ABC and process_instance = 5960 and not exists ( select "X" from PS_SP_BU_GL_NONVW P where P.business_unit = ABC )
Correlated Sub-queries: Predicate Promotion in CSQs
QUERY: select * from ps_jrnl_ln where business_unit = 'ABC and process_instance = 5960 and not exists ( select "X" from PS_SP_BU_GL_NONVW P where P.business_unit = ps_jrnl_ln.business_unit)
Correlated Sub-queries: Predicate Promotion in CSQs
1) ps_jrnl_ln: INDEX PATH Filters: NOT EXISTS <subquery> (1) Index Keys: process_instance business_unit Lower Index Filter: (ps_jrnl_ln.business_unit = 'ABC' AND ps_jrnl_ln.process_instance = 5960 ) Subquery:
--------1) ps_bus_unit_tbl_gl: INDEX PATH (1) Index Keys: business_unit (Key-Only) Lower Index Filter: ps_bus_unit_tbl_gl.business_unit = 'ABC' 2) ps_bus_unit_tbl_fs: INDEX PATH (1) Index Keys: business_unit descr (Key-Only) Lower Index Filter: ps_bus_unit_tbl_fs.business_unit = ps_bus_unit_tbl_gl.business_unit NESTED LOOP JOIN
Constant Subquery Optimization When this filter is checked for the first row, the query can stop immediately, if: its a NOT EXISTS and a row is found its an EXISTS and no rows are found
Correlated Sub-Queries: First Row/SemiJoin
QUERY: UPDATE PS_JRNL_LN SET jrnl_line_status = 3 WHERE BUSINESS_UNIT='ABC' AND PROCESS_INSTANCE=5960
AND EXISTS ( SELECT 'X' FROM PS_COMBO_SEL_06 A WHERE A.SETID='ABC' AND A.COMBINATION='OVERHEAD' AND A.CHARTFIELD='ACCOUNT' AND PS_JRNL_LN.ACCOUNT BETWEEN A.RANGE_FROM_06 AND A.RANGE_TO_06) Estimated Cost: 79 Estimated # of Rows Returned: 1
Correlated Sub-Queries: First Row/SemiJoin
1) sysadm.ps_jrnl_ln: INDEX PATH (1) Index Keys: process_instance business_unit Lower Index Filter: (ps_jrnl_ln.business_unit = 'ABC' AND ps_jrnl_ln.process_instance = 5960 ) 2) informix.a: INDEX PATH (First Row)
Filters: (informix.a.range_to_06 >= ps_jrnl_ln.account AND a.tree_effdt = <subquery> ) (1) Index Keys: setid chartfield combination range_from_06 range_to_06 Lower Index Filter: (a.setid = 'ABC' AND (a.combination = 'OVERHEAD' AND a.chartfield = 'ACCOUNT' ) ) Upper Index Filter: a.range_from_06 <= ps_jrnl_ln.account NESTED LOOP JOIN (Semi Join)
Correlated Sub-Queries: Skip Duplicate
QUERY: update orders set backlog = "Y" where exists ( select "X from items where orders.order_num = items.order_num and stock_num = 6 and manu_code = "SMT ) 1) informix.items: INDEX PATH (Skip Duplicate) Filters: (items.stock_num=6
AND items.manu_code='SMT' ) (1) Index Keys: order_num 2) informix.orders: INDEX PATH (1) Index Keys: order_num Lower Index Filter: orders.order_num = items.order_num NESTED LOOP JOIN