2008-09-11 10 views
19

¿Qué haría para probar que dos consultas son funcionalmente equivalentes, por ejemplo, siempre devolverán el mismo conjunto de resultados?Comprobando la equivalencia de consulta SQL


Como tenía una consulta específica en mente cuando estaba haciendo esto, he acabado haciendo como @dougman sugirió, por encima de aproximadamente el 10% de las filas de las tablas ocupan y la comparación de los resultados, asegurando que no había de resultados de lugar

+0

Supongo que quiere decir exactamente el mismo conjunto de resultados. Eso significa que las mismas columnas (y los mismos tipos de datos) con la misma fila de datos. ¿Correcto? – Craig

+0

Sí, eso es correcto Craig –

Respuesta

12

Lo mejor que puede hacer es comparar las 2 salidas de consulta basadas en un conjunto dado de entradas buscando cualquier diferencia. Decir que siempre devolverán los mismos resultados para todas las entradas realmente depende de los datos.

Para Oracle uno de los mejores si no mejores enfoques (muy eficiente) es aquí (Ctrl + F Al comparar el contenido de dos Tablas):
http://www.oracle.com/technetwork/issue-archive/2005/05-jan/o15asktom-084959.html

que se resume en:

select c1,c2,c3, 
     count(src1) CNT1, 
     count(src2) CNT2 
    from (select a.*, 
       1 src1, 
       to_number(null) src2 
      from a 
     union all 
     select b.*, 
       to_number(null) src1, 
       2 src2 
      from b 
     ) 
group by c1,c2,c3 
having count(src1) <> count(src2); 
+1

enlace actualizado: http://www.oracle.com/technetwork/issue-archive/2005/05-jan/o15asktom-084959.html – MyDogTom

8

Esto me suena como un problema completo de NP. No estoy seguro de que haya una manera segura de probar este tipo de cosas

1

Los proveedores de DBMS han estado trabajando en esto durante mucho, mucho tiempo. Como dijo Rik, es probablemente un problema insoluble, pero no creo que se haya realizado ningún análisis formal sobre la integridad de NP del espacio problemático.

Sin embargo, su mejor opción es aprovechar su DBMS tanto como sea posible. Todos los sistemas DBMS traducen SQL en algún tipo de plan de consulta. Puede utilizar este plan de consulta, que es una versión resumida de la consulta, como un buen punto de partida (el DBMS hará MUCHA optimización, aplanando las consultas en modelos más viables).

NOTA: el moderno DBMS utiliza un analizador "basado en costos" que no es determinista en las actualizaciones de estadísticas, por lo que el planificador de consultas puede cambiar el plan de consultas para consultas idénticas.

En Oracle (dependiendo de su versión), puede decirle al optimizador que cambie del analizador basado en costos al analizador basado en reglas deterministas (esto simplificará el análisis del plan) con una sugerencia SQL, p.

SELECT /*+RULE*/ FROM yourtable 

El optimizador basado en reglas es obsoleta desde 8i pero todavía cuelga alrededor, incluso a través de 10g (no sé 'combate 11). Sin embargo, el analizador basado en reglas es mucho menos sofisticado: la tasa de error es potencialmente mucho más alta.

Para una lectura adicional de una naturaleza más genérica, IBM ha sido bastante prolífico con sus patentes de optimización de consultas. Este sobre un método para convertir SQL a un "plan abstracto" es un buen punto de partida: http://www.patentstorm.us/patents/7333981.html

0

No es así.

Si necesita un alto nivel de confianza de que un cambio en el rendimiento, por ejemplo, no ha cambiado el resultado de una consulta, entonces pruébelo.

Si necesita un alto nivel de confianza ... entonces errrm, pruébela aún más.

El nivel masivo de pruebas no es tan difícil de improvisar para una consulta SQL. Escriba un proceso que iterará alrededor de un conjunto grande/completo de posibles parámetros, y llame a cada consulta con cada conjunto de parámetros y escriba los resultados en las tablas respectivas. Compara las dos tablas y ahí lo tienes.

No es exactamente científico, lo que supongo que fue la pregunta del OP, pero no conozco un método formal para probar la equivalencia.

1

Quizás podría dibujar (a mano) su consulta y los resultados usando Venn Diagrams, y ver si producen el mismo diagrama. Los diagramas de Venn son buenos para representar conjuntos de datos, y las consultas SQL funcionan en conjuntos de datos. Dibujar un Diagrama de Venn puede ayudarlo a visualizar si 2 consultas son funcionalmente equivalentes.

2

Esto es bastante fácil de hacer.

deja para asumir sus consultas se nombran a y b

un menos b

debe darle un conjunto vacío. Si no es así a continuación, las consultas devuelven conjuntos diferentes, y el conjunto de resultados muestra las filas que son diferentes.

luego hacer

b menos un

que debe darle un conjunto vacío. Si lo hace, las consultas devuelven los mismos conjuntos. si no está vacío, las consultas son diferentes en algún aspecto, y el conjunto de resultados muestra las filas que son diferentes.

+0

En SQL Server, puede utilizar EXCEPT para este enfoque - http://msdn.microsoft.com/en-us/library/ms188055%28SQL.90%29.aspx –

+3

Esto solo prueba la equivalencia para ese conjunto particular, no para la consulta en general. – Rik

+0

@rik yep ... esa es la intención. dudo que alguien pueda hacer pruebas con el cálculo relacional – EvilTeach

1

Esto hará el truco. Si esta consulta devuelve cero filas, las dos consultas devuelven los mismos resultados. Como beneficio adicional, se ejecuta como una sola consulta, por lo que no tiene que preocuparse por establecer el nivel de aislamiento para que los datos no cambien entre dos consultas.

select * from ((<query 1> MINUS <query 2>) UNION ALL (<query 2> MINUS <query 1>)) 

Aquí es un script muy útil para hacer esto:

#!/bin/sh 

CONNSTR=$1 
echo query 1, no semicolon, eof to end:; Q1=`cat` 
echo query 2, no semicolon, eof to end:; Q2=`cat` 

T="(($Q1 MINUS $Q2) UNION ALL ($Q2 MINUS $Q1));" 

echo select 'count(*)' from $T | sqlplus -S -L $CONNSTR 
0

CUIDADO! La "equivalencia" funcional se basa a menudo en los datos, y puede "probar" la equivalencia de 2 consultas comparando los resultados de muchos casos y aún estar equivocados una vez que los datos cambian de alguna manera.

Por ejemplo:

SQL> create table test_tabA 
(
col1 number 
) 

Table created. 

SQL> create table test_tabB 
(
col1 number 
) 

Table created. 

SQL> -- insert 1 row 

SQL> insert into test_tabA values (1) 

1 row created. 

SQL> commit 

Commit complete. 

SQL> -- Not exists query: 

SQL> select * from test_tabA a 
where not exists 
(select 'x' from test_tabB b 
where b.col1 = a.col1) 

     COL1 

---------- 

     1 

1 row selected. 

SQL> -- Not IN query: 

SQL> select * from test_tabA a 
where col1 not in 
(select col1 
from test_tabB b) 

     COL1 

---------- 

     1 

1 row selected. 


-- THEY MUST BE THE SAME!!! (or maybe not...) 


SQL> -- insert a NULL to test_tabB 

SQL> insert into test_tabB values (null) 

1 row created. 

SQL> commit 

Commit complete. 

SQL> -- Not exists query: 

SQL> select * from test_tabA a 
where not exists 
(select 'x' from test_tabB b 
where b.col1 = a.col1) 


     COL1 

---------- 

     1 

1 row selected. 

SQL> -- Not IN query: 

SQL> select * from test_tabA a 
where col1 not in 
(select col1 
from test_tabB b) 

**no rows selected.** 
2

realmente debería Cosette: Se comprueba (con una prueba) si la consulta de SQL 2 son ejemplos equivalentes y de apoyo cuando no equivalente. Es la única manera de estar absolutamente seguro, bueno casi;) Incluso puede lanzar 2 consultas en su sitio web y verificar la equivalencia (formal) de inmediato.

Enlace a Cosette: http://cosette.cs.washington.edu/

Enlace al artículo que le da una buena explicación de cómo funciona Cosette: https://medium.com/@uwdb/introducing-cosette-527898504bd6

Si lo que quieres es sólo una solución práctica rápida, también se puede comprobar esta respuesta stackoverflow : [sql - check if two select's are equal]