![]() | |
#1
| |||||||||
| |||||||||
|
| 17567.5 |
| 17567.5 |
| 17567.5 |
|
/------+------\ 175675 8676 112.979 |
|
| 110839 2.26167e+07 |
| 1396.18 |
| 1396.18 |
| 7790.22 |
|
| 175675 2.26167e+07 |
#2
| |||
| |||
|
|
Hi Guys, Db2 LUW V9.5. Consider the following query: SELECT DISTINCT A.SW_ID, B.SW_NAME FROM ASSET.TBL_ASSET_SW A INNER JOIN ASSET.TBL_ASSET_SW_ID B ON (A.SW_ID = B.SW_ID) * * * * * * * * * * * * * INNER JOIN ASSET.TBL_ASSET_MACHINE_ID C ON (A.MACHINE_ID = C.MACHINE_ID) WHERE C.CUSTOMER_ID = 'CC0D6761CD31F72EA7FCC686437DDA98' AND * * * UPPER(B.SW_NAME) LIKE '%ACROBAT%' ORDER BY B.SW_NAME This query is slow. I know that using UPPER(DB_FIELD) like '%%' is bad for performance and bad design. Here is the explain plan for the query (full output may be provided if needed): Access Plan: ----------- * * * * Total Cost: * * * * * * 733996 * * * * Query Degree: * * * * * 1 * * * * * * * * *Rows * * * * * * * * RETURN * * * * * * * * ( * 1) * * * * * * * * *Cost * * * * * * * * * I/O * * * * * * * * * | * * * * * * * * 17567.5 * * * * * * * * TBSCAN * * * * * * * * ( * 2) * * * * * * * * 733996 * * * * * * * * 29959.5 * * * * * * * * * | * * * * * * * * 17567.5 * * * * * * * * SORT * * * * * * * * ( * 3) * * * * * * * * 733994 * * * * * * * * 29959.5 * * * * * * * * * | * * * * * * * * 17567.5 * * * * * * * * ^HSJOIN * * * * * * * * ( * 4) * * * * * * * * 733984 * * * * * * * * 29959.5 * * * * */--------+--------\ * * *17567.5 * * * * * * * 980205 * * *TBSCAN * * * * * * * *NLJOIN * * *( * 5) * * * * * * * *( * 6) * * *2693.42 * * * * * * * 731235 * * * *653 * * * * * * * * 29306.5 * * * *| * * * * * * */------+------\ * * *175675 * * * *8676 * * * * * * 112.979 *TABLE: ASSET * * IXSCAN * * * * * *IXSCAN *TBL_ASSET_SW_ID *( * 7) * * * * * *( * 8) * * * *Q1 * * * * 1674.76 * * * * * 84.1034 * * * * * * * * * 145.253 * * * * * 3.36114 * * * * * * * * * * | * * * * * * * *| * * * * * * * * * 110839 * * * * *2.26167e+07 * * * * * * * INDEX: DB2INST1 * INDEX: DB2INST1 * * * * * * IDX001220131510000 * * *IXPKSW * * * * * * * * * * Q3 * * * * * * * *Q2 According to this plan, we have IXSCAN on ASSET.TBL_ASSET_SW and ASSET.TBL_ASSET_MACHINE_ID, then a NLJOIN. On the other hand, there is a TBSCAN on TBL_ASSET_SW_ID -- maybe caused by UPPER(SW_NAME) like '%ABC%'. Compared to the total query cost (733996), the TBSCAN on TBL_ASSET_SW_ID a Total Cumulative Cost of 2693.42 This represents 0.3% of the returned total cumulative cost. One might disregard that TBSCAN because is represents virtually nothing in terms of total access plan cost. Now let's tune the query: SELECT DISTINCT A.SW_ID, B.SW_NAME FROM ASSET.TBL_ASSET_SW A INNER JOIN ASSET.TBL_ASSET_SW_ID B ON (A.SW_ID = B.SW_ID) * * * * * * * * * * * * * INNER JOIN ASSET.TBL_ASSET_MACHINE_ID C ON (A.MACHINE_ID = C.MACHINE_ID) WHERE C.CUSTOMER_ID = 'CC0D6761CD31F72EA7FCC686437DDA98' AND * * * B.SW_NAME LIKE '%ACROBAT%' ORDER BY B.SW_NAME The plan now looks very different: Access Plan: ----------- * * * * Total Cost: * * * * * * 109695 * * * * Query Degree: * * * * * 1 * * * * * * * * * * * * * *Rows * * * * * * * * * * * * * RETURN * * * * * * * * * * * * * ( * 1) * * * * * * * * * * * * * *Cost * * * * * * * * * * * * * * I/O * * * * * * * * * * * * * * | * * * * * * * * * * * * * 1396.18 * * * * * * * * * * * * * TBSCAN * * * * * * * * * * * * * ( * 2) * * * * * * * * * * * * * 109695 * * * * * * * * * * * * * 5007.48 * * * * * * * * * * * * * * | * * * * * * * * * * * * * 1396.18 * * * * * * * * * * * * * SORT * * * * * * * * * * * * * ( * 3) * * * * * * * * * * * * * 109695 * * * * * * * * * * * * * 5007.48 * * * * * * * * * * * * * * | * * * * * * * * * * * * * 7790.22 * * * * * * * * * * * * * ^HSJOIN * * * * * * * * * * * * * ( * 4) * * * * * * * * * * * * * 109690 * * * * * * * * * * * * * 5007.48 * * * * * * * * * /---------+----------\ * * * * * * * 179747 * * * * * * * * * *8676 * * * * * * * NLJOIN * * * * * * * * * IXSCAN * * * * * * * ( * 5) * * * * * * * * * ( * 8) * * * * * * * 107996 * * * * * * * * * 1674.75 * * * * * * * 4862.23 * * * * * * * * *145.253 * * * * */------+-------\ * * * * * * * *| * * *1396.18 * * * * * *128.742 * * * *110839 * * *TBSCAN * * * * * * IXSCAN * * INDEX: DB2INST1 * * *( * 6) * * * * * * ( * 7) * IDX001220131510000 * * *2673.42 * * * * * *75.4497 * * * * *Q3 * * * *653 * * * * * * *3.01481 * * * *| * * * * * * * * *| * * *175675 * * * * * 2.26167e+07 *TABLE: ASSET * * * INDEX: DB2INST1 *TBL_ASSET_SW_ID *IDX002081020460000 * * * *Q1 * * * * * * * * Q2 This query has good response time. We still have the TBSCAN on TBL_ASSET_SW_ID and an IXSCAN on TBL_ASSET_SW, then they both are NLJOINed. What confuses me is that TBSCAN cost on TBL_ASSET_SW_ID is still virtually the same (cost = 2673) and still represents 2% of overall total cost. Nevertheless, the overall access plan was been influenced by a bad predicate, even though the plan for that table itself is not much different on both scenarios. What am I missing here? Thanks, |
#3
| |||
| |||
|
|
Hello Michel, I think you should take a closer look on the estimated cardinality of the TBSCAN operation. While the cost of the tablescan is practically identical for both situations, the expected result set is much larger when you use the UPPER-function. Logical, right? The biggest part of the work is IO, and with the upper-function you add a little CPU to the comparison, so the cost is close. In this case, DB2 estimates that with using UPPER, over 10 times more rows will qualify for your search, and that definitively has an impact on the rest of the access plan. In your case, the work that needs to be done with the result from your tablescan. If you don't agree on the choices DB2 makes, did you compare the estimated cardinality with the real one? |
#4
| |||
| |||
|
|
Hi Frederick, Thanks for your response. Let me share parts of the plan for both queries. Slow running query: *5) TBSCAN: (Table Scan) * * * * * * * * Cumulative Total Cost: * * * * *2693.42 * * * * * * * * Cumulative CPU Cost: * * * * * *5.06243e+08 * * * * * * * * Cumulative I/O Cost: * * * * * *653 * * * * * * * * Cumulative Re-Total Cost: * * * 117..402 * * * * * * * * Cumulative Re-CPU Cost: * * * * 4..58865e+08 * * * * * * * * Cumulative Re-I/O Cost: * * * * 0 * * * * * * * * Cumulative First Row Cost: * * *25.1504 * * * * * * * * Estimated Bufferpool Buffers: * 653 * * * * * * * * Output Streams: * * * * * * * * -------------- * * * * * * * * * * * * 2) To Operator #4 * * * * * * * * * * * * * * * * Estimatednumber of rows: 17567.5 * * * * * * * * * * * * * * * * Number ofcolumns: * * * * * * *2 * * * * * * * * * * * * * * * * Subquery predicate ID: * * * * *Not Applicable * * * * * * * * * * * * * * * * Column Names: * * * * * * * * * * * * * * * * ------------ * * * * * * * * * * * * * * * * +Q1.SW_NAME+Q1.SW_ID Fast Query: *6) TBSCAN: (Table Scan) * * * * * * * * Cumulative Total Cost: * * * * *2673.42 * * * * * * * * Cumulative CPU Cost: * * * * * *4.28068e+08 * * * * * * * * Cumulative I/O Cost: * * * * * *653 * * * * * * * * Cumulative Re-Total Cost: * * * 97.4006 * * * * * * * * Cumulative Re-CPU Cost: * * * * 3..80689e+08 * * * * * * * * Cumulative Re-I/O Cost: * * * * 0 * * * * * * * * Cumulative First Row Cost: * * *26.8954 * * * * * * * * Estimated Bufferpool Buffers: * 653 * * * * * * * * Output Streams: * * * * * * * * -------------- * * * * * * * * * * * * 2) To Operator #5 * * * * * * * * * * * * * * * * Estimatednumber of rows: 1396.18 * * * * * * * * * * * * * * * * Number ofcolumns: * * * * * * *2 * * * * * * * * * * * * * * * * Subquery predicate ID: * * * * *Not Applicable * * * * * * * * * * * * * * * * Column Names: * * * * * * * * * * * * * * * * ------------ * * * * * * * * * * * * * * * * +Q1.SW_NAME+Q1.SW_ID If we look at the CPU Costs, there is an approx. 20% decreased cost in the Fast Query. Also, the I/O Cost is exactly the same on both queries. Having that in mind, why is the total cost for both plans so different ? I understand that having less estimated rows makes DB2 choose other access plans with the other operators, tables and indexes. But since this TBSCAN has a direct impact on all the access plan, shouldn't it be more visible for less experienced DBAs that this operator has direct impact on the total query performance ? One may read the total cost of the original query (733996) and then compare it to this TBSCAN cost (2693). The first direct (and WRONG !!) conclusion is that a DBA should not focus his attention on this TBSCAN ... but he should !!! The real cardinality returned by this TBSCAN is approx 250 rows. Very different from the estimated rows on the good query (~1400) and bad query (~17000). Thanks, -M Hello Michel, I think you should take a closer look on the estimated cardinality of the TBSCAN operation. While the cost of the tablescan is practically identical for both situations, the expected result set is much larger when you use the UPPER-function. Logical, right? The biggest part of the work is IO, and with the upper-function you add a little CPU to the comparison, so the cost is close. In this case, DB2 estimates that with using UPPER, over 10 times more rows will qualify for your search, and that definitively has an impact on the rest of the access plan. In your case, the work that needs to be done with the result from your tablescan. If you don't agree on the choices DB2 makes, did you compare the estimated cardinality with the real one? |
#5
| |||
| |||
|
#6
| |||
| |||
|
|
Hi Fred, Here is my final question about this ![]() In my bad query: The use of UPPER(SW_NAME) like '%ABC%' forced a TBSCAN on B (TBL_ASSET_SW_ID). The other tables (A and C) were IXSCANned using predicate (A.MACHINE_ID = C.MACHINE_ID), *then this result was HSJOINed with the TBSCAN on B. In my good query: The use of SW_NAME like '%ABC%' forced again a TBSCAN on B (TBL_ASSET_SW_ID). DB2 now chose to IXSCAN table A on field (A.SW_ID), then NLJOINed both (A and B). It then IXSCANed table C and HSJoined with the previous result (A and B). Notice that DB2 chose different indexes on both plans. Is this due to different expected number of rows while using UPPER(SW_NAME) like %% and without the use of UPPER () ? I wonder if DB2 always forced the use of index A.SW_ID a better result would be achieved, even with the UPPER(SW_NAME) predicate ? Thanks again, -M |
#7
| |||
| |||
|
|
What am I missing here? |
#8
| |||
| |||
|
|
On Nov 17, 6:28*am, Michel Esber <smes... (AT) gmail (DOT) com> wrote: What am I missing here? The slowness is almost certainly coming from the hash join (op 4 in the first query), not the table scan. *Are you getting hash join overflows in the first query, but not the second query? In the first query, DB2 is estimating the the build table (the result of the NLJOIN) will have ~980K rows, and the probe table will have ~17.5K rows. *In the second query, the build table will have ~8.6K rows, and the probe will have ~180K rows. Are the optimizer's estimates accurate? |
#9
| |||
| |||
|
|
In your bad version, DB2 joins your A and C together first. That's at least 22M records that are scanned and probably hashed afterwards and that's probably what makes your query so slow. I'm actually surprised that he still executes a hash join in the last scenario. Do you have an index on C.MACHINE_ID? |
.
.
#10
| |||
| |||
|
|
The slowness is almost certainly coming from the hash join (op 4 in the first query), not the table scan. *Are you getting hash join overflows in the first query, but not the second query? |
|
In the first query, DB2 is estimating the the build table (the result of the NLJOIN) will have ~980K rows, and the probe table will have ~17.5K rows. *In the second query, the build table will have ~8.6K rows, and the probe will have ~180K rows. Are the optimizer's estimates accurate? |
![]() |
| Thread Tools | |
| Display Modes | |
| |