Bem, eu sou capaz de replicá-lo e a razão por trás de tal comportamento é a interpretação de predicados da Oracle.
Versão do SO e Oracle onde isso pode ser reproduzido:
SQL> host ver
Microsoft Windows [Version 6.1.7601]
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 64-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL>
No primeiro caso, o predicado é modificado para
filter("D"."DT" IS NOT NULL)
enquanto na segunda consulta, o predicado funciona conforme fornecido filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd hh24:mi:ss') OR "D"."DT">[email protected]!)
SQL> select count(*)
2 from aaa d
3 where (d.dt > sysdate)
4 or d.dt < to_date('20130120','yyyymmdd')
5 /
COUNT(*)
----------
15
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 15 | 135 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT" IS NOT NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from aaa d
3 where d.dt < to_date('20130120','yyyymmdd')
4* or (d.dt > sysdate)
SQL>
/
COUNT(*)
----------
7
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 7 | 63 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') OR "D"."DT">[email protected]!)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
Não consegui descobrir esse comportamento do Oracle, bem possível que alguns especialistas possam explicar isso.
Novamente no terceiro exemplo, os predicados são usados corretamente.
filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd hh24:mi:ss') OR INTERNAL_FUNCTION("D"."DT")+1>[email protected]!+1)
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from aaa d
3 where (d.dt + 1 > sysdate + 1)
4* or d.dt < to_date('20130120','yyyymmdd')
SQL> /
COUNT(*)
----------
7
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 7 | 63 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') OR INTERNAL_FUNCTION("D"."DT")+1>[email protected]!+1)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
É bastante óbvio que o mesmo não pode ser reproduzido do Oracle Versão 11.2.0.2.0 e 11.2.0.3.0 em servidores Linux.
Atualização:
Como Alex Poole mencionado nos comentários - "Isso pode ser o bug 9495697, 'Resultados errados podem ser retornados para uma consulta contendo dois predicados de filtro OR na mesma coluna, onde o outro lado de um predicado não é uma constante de tempo de compilação (por exemplo. É um bind, sysdate, etc.)"