2011-09-07 8 views
12
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 

espero que esta consulta a fallar, debido fecha no válida, pero devuelve 0éxito inesperado consulta

El plan para esta consulta muestra que el 8 de paso de la cláusula inválida es procesados:

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      

Si nos comente AND workflow_status IN (7, 12, 17) estado - como era de esperar entonces que obtenemos ORA-01858: a non-numeric character was found where a numeric was expected

Si se comentan a cabo AND workflow_finished < TO_DATE ('wtf', 'dd.mm.yyyy') entonces obtenemos cantidad de registros que se ajustan a esas condiciones (> 0)

¿Cómo es esto posible?

UPD:

La sugerencia /*+no_index(rps2_workflow) */ no cambia nada (mientras que en el plan se ve que se lleva a cabo 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 
+0

@BoltClock: aw, no se puede poner sql al final de la lista de etiquetas: -S El problema es específico de Oracle, no solo una pregunta general de sql – zerkms

+0

Supongo que el optimizador no encontró registros (usando índices) para el trabajador 159 con un estado de 7, 12 o 17, por lo que no se molestó en evaluar el resto de la consulta. Cuando elimina la comprobación de estado, se encuentran algunos registros, por lo que debe evaluar la función TO_DATE y provocar el error. Es difícil decir con certeza qué está haciendo el optimizador de consultas ... – Sparky

+0

@Sparky: mire el último párrafo, si eliminamos la consulta "incorrecta", devuelve las filas. También lo pensé en un momento, pero ** hay ** registros con estados especificados – zerkms

Respuesta

3

probablemente encontrado que cada registro que satisface todas las demás condiciones tiene un campo NULLworkflow_finished.

Y cualquier cosa en comparación con NULL es desconocida, por lo que no es necesario evaluar el otro operando.

+1

+1 Solo un punto menor: cualquier cosa en comparación con NULL es desconocida, no es falsa, aunque no hace ninguna diferencia aquí. –

7

Si el optimizador decide que no necesita evaluar una función, no lo hará, por lo que la función nunca va a lanzar excepciones:

select 1 from dual where 1 = 1 OR to_date('asdasdasd','asdasdasdas') > sysdate ; 

     1 
---------- 
     1 

la función lanza una excepción sólo si realmente se evalúa:

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 

Sin embargo, si el analizador puede decidir estáticamente que la consulta no es válida - ya que la función tiene el tipo incorrecto de argumentos o de la consulta tiene tipos válidos, entonces el analizador emitirá una excepción antes de que el optimizador consigue un swing en él:

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 
+0

Aunque estés absolutamente en lo correcto, no es una respuesta. Porque el problema era un poco más profundo (no a nivel de predicado, sino a nivel de operando). Y alexisdm lo ha adivinado correctamente. +1 de todos modos – zerkms

+0

Ah, no he leído todos los comentarios de "leer más" antes de responder :) –

+0

pero de todos modos has hecho un excelente trabajo. Esta información definitivamente será útil para cualquier lector adicional. Si alexisdm no pone su respuesta, verificaré la tuya (y añadiré que el caso causó ese comportamiento "extraño") – zerkms