This behaviour could be explained by insufficient information available to the query optimizer in the absence of a literal value.
When the literal value is supplied in the predicate, the optimizer can use the value distribution statistics for tableA.identcol
to estimate how many rows might match the condition. Apparently, distribution is such that, given the literal value supplied, it considers index-based access better.
When instead you supply a subquery, the optimizer has no way of knowing what identval
will be returned, so it makes a guess, which in your case turns out to be suboptimal.
To achive a more consistent optimization outcome you'll need to supply the optimizer with additional information. There are a few options you might try.
- Create a statistical view, something like
create view sv1 as select Col1 from TableA, ParamTable where TableA.identcol > ParamTable.identval
(and drop the bigint()
from your query -- no need to confuse the optimizer even more). You will then need to enable statistical view optimization (alter view sv1 enable query optimization
) and collect distribution statistics (runstats on table sv1 with distribution
). However, seeing that ParamTable
has only one row in it, one might assume that it changes quite frequently, so you'll need to make sure that statistics are updated each time ParamTable.identval
changes.
Provide explicit selectivity estimate to the optimizer: Select Col1 from TableA where identcol > (select bigint(identval) from ParamTable) selectivity 0.001
. Before you can do that, you will need to set the DB2 registry variable enabling this behaviour (db2set DB2_SELECTIVITY=ALL
) and restart the instance. 0.001
indicates the proportion of the table, in this case 0.1%, that satisfies the condition. Replace 0.001
with the realistic estimate of the proportion of matching rows.
Create an index on TableA (identcol, Col1)
if it does not already exist (and collect statistics for it) -- this might enable index-only access.