Why does a query with a sub-select cost less than query with a constant in Oracle
I've got an SQL-table with some million entries and I tried to query how much entries are older than 60 days (Oracle 11.2.0.1.0).
For this experiment I used 3 different versions of the select-statement:
(The cost-value is given by TOAD for Oracle V. 9.7.2.5)
Cost: 65select count(*) from fman_file where dateadded >= (select sysdate - 60 from dual)
Cost: 1909select count(*) from fman_file where dateadded >= sysdate - 60
Cost: 1884select count(*) from fman_file where dateadded >= sysdate - numtodsinterval(60,'day')
Cost: 1823 (The 10.10.2009 is just an example-date!!!)select count(*) from fman_file where dateadded >= '10.10.2009'
I don't have the accurate time-values for all queries in mind, but the first one really was the fastest.
So I tried some more select-queries with other subselects (like (Select 1000 from dual)) and they were (sometimes WAY) faster than the others with constant-values. It even seems that this "WHATEVER" (Bug/Feature) is happening in MySQL too.
So can anyone tell me why the first query is (way) faster that the others?
Greetz
P.S.: This ain't about the sydate! The question is WHY IS THE VARIATION WITH THE (Select) FASTER THAN THE OT开发者_如何学CHERS? (with a little focus on Select-Variation(1.) vs. Constant-Variation (4.))
Found some hints in my copy of "Cost-Based Oracle Fundamentals" by Jonathan Lewis in chapter 6 "surprising sysdate". This seems to apply to 9i, probably also later versions.
The optimizer treats sysdate (and trunc(sysdate) and a few other functions of sysdate) as known constants at parse time, but sysdate + N becomes an unknown, and gets the same treatment as a bind variable - which means a fixed 5% selectivity. (Note in particular that sysdate + 0 will give a different cardinality from sysdate.)
Apparently the optimizer also recognizes the select sysdate from dual
as a known constant.
Tom Kyte:
The advantage to dual is the optimizer understands dual is a special one row, one column table -- when you use it in queries, it uses this knowledge when developing the plan.
Did you re-try numbers 2-4 with () around the calculation after the >= -- it seems to me the first statement is the only one where it calculates that value once -- for all the others it recalculates on every row. eg:
select count(*) from fman_file where dateadded >= (SELECT sysdate - 60)
select count(*) from fman_file where dateadded >= (SELECT (sysdate - numtodsinterval(60,'day'))
select count(*) from fman_file where dateadded >= (SELECT CONVERT(datetime,'10.10.2009'))
NB -- don't know the syntax to convert to a datetime in Oracle -- but you get the idea.
You could try using Explain Plan
. This will show you what the queries are doing and the differences between them.
A couple of links to setup and use explain plan:
http://download.oracle.com/docs/cd/B10500_01/server.920/a96533/ex_plan.htm
http://www.adp-gmbh.ch/ora/explainplan.html
instead of using (select sysdate - 60 from dual) i'd rather recommend you using a bind variable, which value is calculated before the query become executed
精彩评论