Ответ 1
Вероятно, было обнаружено, что каждая запись, удовлетворяющая всем другим условиям, имеет поле NULL
workflow_finished
.
И ничего по сравнению с NULL
неизвестно, поэтому ему не нужно оценивать другой операнд.
SELECT COUNT (*)
FROM rps2_workflow
WHERE workflow_added > TO_DATE ('01.09.2011', 'dd.mm.yyyy')
AND workflow_finished < TO_DATE ('wtf', 'dd.mm.yyyy')
AND workflow_status IN (7, 12, 17)
AND workflow_worker = 159
Я ожидаю, что этот запрос завершится неудачно из-за недопустимой даты, но он вернет 0
План этого запроса показывает, что на 8-м шаге обработано недопустимое предложение :
8 TABLE ACCESS BY INDEX ROWID TABLE RPS2.RPS2_WORKFLOW Object Instance: 1 Filter Predicates: ("WORKFLOW_STATUS"=7 OR "WORKFLOW_STATUS"=12 OR "WORKFLOW_STATUS"=17) AND SYS_EXTRACT_UTC("WORKFLOW_FINISHED")<SYS_EXTRACT_UTC(TO_DATE('wtf','dd.mm.yyyy')) Cost: 11 Bytes: 33 Cardinality: 1 CPU Cost: 8 M IO Cost: 10 Time: 1
Если мы прокомментируем условие AND workflow_status IN (7, 12, 17)
- тогда, как мы ожидаем, получим ORA-01858: a non-numeric character was found where a numeric was expected
Если мы прокомментируем AND workflow_finished < TO_DATE ('wtf', 'dd.mm.yyyy')
, то получим количество записей, которые соответствуют этим условиям ( > 0)
Как это возможно?
UPD
Подсказка /*+no_index(rps2_workflow) */
ничего не меняет (тогда как в плане мы видим, что выполняется fullscan)
SELECT STATEMENT ALL_ROWSCost: 254 Bytes: 31 Cardinality: 1 CPU Cost: 34 M IO Cost: 248 Time: 4
2 SORT AGGREGATE Bytes: 31 Cardinality: 1
1 TABLE ACCESS FULL TABLE RPS2.RPS2_WORKFLOW Object Instance: 1 Filter Predicates: "WORKFLOW_WORKER"=159 AND ("WORKFLOW_STATUS"=7 OR "WORKFLOW_STATUS"=12 OR "WORKFLOW_STATUS"=17) AND SYS_EXTRACT_UTC("WORKFLOW_ADDED")>SYS_EXTRACT_UTC(TIMESTAMP' 2011-09-01 00:00:00') AND SYS_EXTRACT_UTC("WORKFLOW_FINISHED")<SYS_EXTRACT_UTC(TO_DATE('wtf','dd.mm.yyyy')) Cost: 254 Bytes: 31 Cardinality: 1 CPU Cost: 34 M IO Cost: 248 Time: 4
Вероятно, было обнаружено, что каждая запись, удовлетворяющая всем другим условиям, имеет поле NULL
workflow_finished
.
И ничего по сравнению с NULL
неизвестно, поэтому ему не нужно оценивать другой операнд.
Если оптимизатор решает, что ему не нужно оценивать функцию, он не будет, поэтому функция никогда не будет генерировать исключения:
select 1 from dual where 1 = 1 OR to_date('asdasdasd','asdasdasdas') > sysdate ;
1
----------
1
Функция вызывает исключение только в том случае, если она действительно получает оценку:
SQL> select 1 from dual where 1 = 1 AND to_date('asdasd','asdas') > sysdate ;
select 1 from dual where 1 = 1 AND to_date('asdasd','asdas') > sysdate
*
ERROR at line 1:
ORA-01821: date format not recognized
Однако, если синтаксический анализатор может решить статически, что запрос недействителен - поскольку функция имеет неправильный тип аргументов или запрос имеет недопустимые типы, тогда синтаксический анализатор вызовет исключение, прежде чем оптимизатор получит на него колебание:
SQL> select 1 from dual where 1 = 1 or to_date('asdasdasd',0) > sysdate ;
select 1 from dual where 1 = 1 or to_date('asdasdasd',0) > sysdate
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected DATE got NUMBER
SQL> select 1 from dual where 1 = 1 or to_date('asdasdasd','asdasdasdas') > 42 ;
select 1 from dual where 1 = 1 or to_date('asdasdasd','asdasdasdas') > 42
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected DATE got NUMBER