Execution plan dependent Query Results - Sorting
Hi,
do you think execution plans are only the compiled access plan on which
data will retrieved hopefully with low costs and good response time?
Execution plans can also have influence on the result set of your SQL!
Happended day ago in my current project. A milestone was put on a
separate database. After first tests we detected some lists were not
sorted. We support paged lists. On database side a window of rows sorted by a column will be retrieved - enriched with country coded texts.
We were surprised because we did not expect from the sorted window to get unsorted output. Here the SQL:
SELECT
Company.Legalname,
Company.*,
V1.VALUE AS Industry,
V2.VALUE AS Industrysubtype,
V3.VALUE AS Companystatetext,
V4.VALUE AS Bgsdescription,
V5.VALUE AS Legalform,
V6.VALUE AS Region,
V7.VALUE AS Countrytext
FROM Isis.Industrytext V1,
Isis.Industrysubtypetext V2,
Isis.Companystatetext V3,
Isis.Bgscodetext V4,
Isis.Legalformtext V5,
Isis.Regiontext V6,
Isis.Countrytext V7,
(SELECT /*+ FIRST_ROWS */
Iq.*,
FROM (SELECT Company.*
FROM (SELECT *
FROM Isis.Company
WHERE Company.Isis_Prefered = 1) Company
WHERE Company.Companystate <> 5
AND Upper(TRIM(Company.City)) LIKE Upper(TRIM('
ORDER BY Company.Legalname ASC) Iq
WHERE Rownum <= 15) Company
WHERE z_r_n >= 1
AND (V1.Key(+) = Company.Industrykey AND V1.Locale(+) = 'en-GB' AND
V2.Key(+) = Company.Industrysubtypekey AND V2.Locale(+) = 'en-GB' AND
V3.Key(+) = Company.Companystate AND V3.Locale(+) = 'en-GB' AND
V4.Key(+) = Company.Bgscode AND V4.Locale(+) = 'en-GB' AND
V5.Key(+) = Company.Legalformkey AND V5.Locale(+) = 'en-GB' AND
V6.Key(+) = Company.Regionkey AND V6.Locale(+) = 'en-GB' AND
V7.Key(+) = Company.Countryisocode AND V7.Locale(+) = 'en-GB')
HASH JOIN OUTER Cost=22 Cardinality=5 Bytes=4960 CPU cost=4397817
NESTED LOOPS OUTER Cost=18 Cardinality=4 Bytes=3892 CPU cost=2322090
NESTED LOOPS OUTER Cost=15 Cardinality=3 Bytes=2862 CPU cost=2275522
NESTED LOOPS OUTER Cost=12 Cardinality=3 Bytes=2616 CPU cost=2210139
NESTED LOOPS OUTER Cost=9 Cardinality=3 Bytes=2547 CPU cost=2163570
NESTED LOOPS OUTER Cost=6 Cardinality=3 Bytes=2448 CPU cost=2117001
NESTED LOOPS OUTER Cost=6 Cardinality=3 Bytes=2388 CPU cost=2092487
VIEW Object owner=ISIS Cost=6 Cardinality=3 Bytes=2337
COUNT STOPKEY
VIEW Object owner=ISIS Cost=6 Cardinality=3 Bytes=2298
SORT ORDER BY STOPKEY Cost=6 Cardinality=3 Bytes=759 CPU cost=2067973
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=COMPANY_ISIS_MVX Cost=5 Cardinality=3 Bytes=759 CPU cost=32858
INDEX RANGE SCAN Object owner=ISIS Object name=COMPANY_ISIS_MVX_FX03 Cost=2 Cardinality=4 CPU cost=8009
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=LEGALFORMTEXT Cost=1 Cardinality=1 Bytes=17 CPU cost=8172
INDEX UNIQUE SCAN Object owner=ISIS Object name=LEGALFORMTEXT_UK35 Cost=1 Cardinality=2 CPU cost=8172
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=REGIONTEXT Cost=1 Cardinality=1 Bytes=20 CPU cost=8172
INDEX UNIQUE SCAN Object owner=ISIS Object name=REGIONTEXT_UK36 Cost=1 Cardinality=2 CPU cost=8172
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=INDUSTRYTEXT Cost=2 Cardinality=1 Bytes=33 CPU cost=15523
INDEX UNIQUE SCAN Object owner=ISIS Object name=INDUSTRYTEXT_UK33 Cost=1 Cardinality=2 CPU cost=8172
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=INDUSTRYSUBTYPETEXT Cost=2 Cardinality=1 Bytes=23 CPU cost=15523
INDEX UNIQUE SCAN Object owner=ISIS Object name=INDUSTRYSUBTYPETEXT_UK34 Cost=1 Cardinality=2 CPU cost=8172
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=BGSCODETEXT Cost=2 Cardinality=1 Bytes=82 CPU cost=21795
INDEX UNIQUE SCAN Object owner=ISIS Object name=BGSCODETEXT_UK31 Cost=1 Cardinality=2 CPU cost=14443
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=COUNTRYTEXT Cost=2 Cardinality=1 Bytes=19 CPU cost=15523
INDEX UNIQUE SCAN Object owner=ISIS Object name=COUNTRYTEXT_UK32 Cost=1 Cardinality=2 CPU cost=8172
TABLE ACCESS FULL Object owner=ISIS Object name=COMPANYSTATETEXT Cost=4 Cardinality=7 Bytes=133 CPU cost=39528
If you review the execution plan you see an inner sort operation, followed by nested loops. Nested loops do not change the order of the rowset. But the last operation is a hash join due to a full table scan of the COMPANYSTATETEXT table. Hashing means access via hash code - this means no sorting. The result set was unsorted!
The reason for the FULL TABLE scan was the cardinality of the COMPANYSTATETEXT table. With only 7 rows CBO will not use the index for access.
Using Hints
An index Hint should help to avoid the hash join and result in a sorted result set. And this worked:
SELECT /*+ Index (v3, COMPANYSTATETEXT_UK30) */
Company.Legalname,
Company.*,
V1.VALUE AS Industry,
V2.VALUE AS Industrysubtype,
V3.VALUE AS Companystatetext,
V4.VALUE AS Bgsdescription,
V5.VALUE AS Legalform,
V6.VALUE AS Region,
V7.VALUE AS Countrytext
FROM Isis.Industrytext V1,
Isis.Industrysubtypetext V2,
Isis.Companystatetext V3,
Isis.Bgscodetext V4,
Isis.Legalformtext V5,
Isis.Regiontext V6,
Isis.Countrytext V7,
(SELECT /*+ FIRST_ROWS */
Iq.*,
Rownum AS z_r_n
FROM (SELECT Company.*
FROM (SELECT *
FROM Isis.Company
WHERE Company.Isis_Prefered = 1) Company
WHERE Company.Companystate <> '5'
AND Upper(TRIM(Company.City)) LIKE Upper(TRIM('BERLIN'))
ORDER BY Company.Legalname ASC) Iq
WHERE Rownum <= 15) Company
WHERE z_r_n >= 1
AND (V1.Key(+) = Company.Industrykey AND V1.Locale(+) = 'en-GB' AND
V2.Key(+) = Company.Industrysubtypekey AND V2.Locale(+) = 'en-GB' AND
V3.Key(+) = Company.Companystate AND V3.Locale(+) = 'en-GB' AND
V4.Key(+) = Company.Bgscode AND V4.Locale(+) = 'en-GB' AND
V5.Key(+) = Company.Legalformkey AND V5.Locale(+) = 'en-GB' AND
V6.Key(+) = Company.Regionkey AND V6.Locale(+) = 'en-GB' AND
V7.Key(+) = Company.Countryisocode AND V7.Locale(+) = 'en-GB')
NESTED LOOPS OUTER Cost=25 Cardinality=5 Bytes=4960 CPU cost=2384047
NESTED LOOPS OUTER Cost=21 Cardinality=4 Bytes=3892 CPU cost=2321955
NESTED LOOPS OUTER Cost=15 Cardinality=3 Bytes=2862 CPU cost=2275522
.... TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=BGSCODETEXT Cost=2 Cardinality=1 Bytes=82 CPU cost=21795
INDEX UNIQUE SCAN Object owner=ISIS Object name=BGSCODETEXT_UK31 Cost=1 Cardinality=2 CPU cost=14443
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=COMPANYSTATETEXT Cost=3 Cardinality=1 Bytes=19 CPU cost=15478
INDEX FULL SCAN Object owner=ISIS Object name=COMPANYSTATETEXT_UK30 Cost=2 Cardinality=1 CPU cost=8205
TABLE ACCESS BY INDEX ROWID Object owner=ISIS Object name=COUNTRYTEXT Cost=2 Cardinality=1 Bytes=19 CPU cost=15523
INDEX UNIQUE SCAN Object owner=ISIS Object name=COUNTRYTEXT_UK32 Cost=1 Cardinality=2 CPU cost=8172
Wow really great! the hint worked! Last operation is nested loop instead of hash join.
But what if the index name COMPANYSTATETEXT_UK30 of COMPANYSTATETEXT would be changed? The hint would have no effect. Then the order of the result set would be gone away!
This is not a solid solution.
The only chance is to sort again! This way only assures the stability of an ordered result set.
SELECT Company.Legalname,
Company.*,
V1.VALUE AS Industry,
V2.VALUE AS Industrysubtype,
V3.VALUE AS Companystatetext,
V4.VALUE AS Bgsdescription,
V5.VALUE AS Legalform,
V6.VALUE AS Region,
V7.VALUE AS Countrytext
FROM Isis.Industrytext V1,
Isis.Industrysubtypetext V2,
Isis.Companystatetext V3,
Isis.Bgscodetext V4,
Isis.Legalformtext V5,
Isis.Regiontext V6,
Isis.Countrytext V7,
(SELECT /*+ FIRST_ROWS */
Iq.*,
Rownum AS z_r_n
FROM (SELECT Company.*
FROM (SELECT *
FROM Isis.Company
WHERE Company.Isis_Prefered = 1) Company
WHERE Company.Companystate <> 5
AND Upper(TRIM(Company.City)) LIKE Upper(TRIM('BERLIN'))
ORDER BY Company.Legalname ASC)
Iq
-- INNER SORT
WHERE Rownum <= 15) Company
WHERE z_r_n >= 1
AND (V1.Key(+) = Company.Industrykey AND V1.Locale(+) = 'en-GB' AND
V2.Key(+) = Company.Industrysubtypekey AND V2.Locale(+) = 'en-GB' AND
V3.Key(+) = Company.Companystate AND V3.Locale(+) = 'en-GB' AND
V4.Key(+) = Company.Bgscode AND V4.Locale(+) = 'en-GB' AND
V5.Key(+) = Company.Legalformkey AND V5.Locale(+) = 'en-GB' AND
V6.Key(+) = Company.Regionkey AND V6.Locale(+) = 'en-GB' AND
V7.Key(+) = Company.Countryisocode AND V7.Locale(+) = 'en-GB')
ORDER BY Company.Legalname ASC -- Last Operation is SORT
- The resulting Execution Plan (compressed)
SORT ORDER BY Cost=23 Cardinality=5 Bytes=4925 CPU cost=6433240
HASH JOIN OUTER Cost=22 Cardinality=5 Bytes=4925 CPU cost=4397817
NESTED LOOPS OUTER Cost=18 Cardinality=4 Bytes=3864 CPU cost=2322090
NESTED LOOPS OUTER Cost=15 Cardinality=3 Bytes=2841 CPU ...
Even the hash join appeared again - the last operation - the (last) SORT brings the expected results!
Karl
