2008-09-11 3 views
19

Как бы вы доказали, что два запроса функционально эквивалентны, например, они всегда будут возвращать одинаковый набор результатов.Проверка эквивалентности запросов SQL


Как я уже имел определенный запрос в виду, когда я делал это, я закончил тем, что делал, как @dougman предложил, в течение примерно 10% строк соответствующих таблиц и сравнение результатов, обеспечивая не было из разместить результаты.

+0

Я предполагаю, что вы имеете в виду точно такой же набор результатов. Это означает, что одни и те же столбцы (и одни и те же типы данных) имеют одни и те же данные строки. Верный? – Craig 2008-09-11 15:37:24

+0

Yep, thats right Craig – 2008-09-17 06:57:04

ответ

12

Лучшее, что вы можете сделать, это сравнить 2 выхода запроса на основе заданного набора входов, ищущих любые различия. Сказать, что они всегда будут возвращать одинаковые результаты для всех входов, действительно зависят от данных.

Для Oracle одним из лучших, если не лучшие подходы (очень эффективно) здесь (Ctrl + F Сравнение содержимого двух таблиц):
http://www.oracle.com/technetwork/issue-archive/2005/05-jan/o15asktom-084959.html

, которая сводится к:

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

обновленная ссылка: http://www.oracle.com/technetwork/issue-archive/2005/05-jan/o15asktom-084959.html – MyDogTom 2014-10-22 07:00:07

8

Это звучит для меня как проблема с NP. Я не уверен, что есть верный способ для доказательства такого рода вещей.

1

Поставщики СУБД работали над этим очень и очень долгое время. Как сказал Рик, это , вероятно, проблема неразрешимая, но я не думаю, что какой-либо формальный анализ NP-полноты проблемного пространства был выполнен.

Однако, самое лучшее, чтобы максимально использовать ваши СУБД. Все системы СУБД переводят SQL в какой-то план запросов. Вы можете использовать этот план запросов, который является абстрактной версией запроса, в качестве хорошей отправной точки (СУБД будет выполнять LOTS оптимизации, сглаживая запросы на более работоспособные модели).

ПРИМЕЧАНИЕ. В современной СУБД используется анализатор, основанный на затратах, который не является детерминированным в отношении обновлений статистики, поэтому планировщик запросов со временем может изменить план запроса для идентичных запросов.

В Oracle (в зависимости от вашей версии) вы можете сказать оптимизатору перейти от анализатора, основанного на затратах, к анализу на основе определения основанного на правилах (это упростит анализ плана) с помощью подсказки SQL, например.

SELECT /*+RULE*/ FROM yourtable 

правило оптимизатора является устаревшим с 8i, но она до сих пор висит вокруг, даже через 10 г (не знаю насчет 11). Однако анализатор, основанный на правилах, гораздо менее изощренен: вероятность ошибки намного выше.

Для дальнейшего ознакомления с более общим характером IBM довольно плодотворна благодаря своим патентам на оптимизацию запросов. Это один из способов преобразования SQL в «абстрактный план» является хорошей отправной точкой: http://www.patentstorm.us/patents/7333981.html

0

У вас нет.

Если вам нужна высокая степень уверенности в том, что изменение производительности, например, не изменило выход запроса, то проверьте его.

Если вам нужен действительно высокий уровень уверенности .. тогда errrm, проверьте его еще больше.

Тестирование на уровне массива не так сложно скомбинировать для SQL-запроса. Напишите proc, который будет перебирать вокруг большого/полного набора возможных паразитных элементов и вызывать каждый запрос с каждым набором параметров и записывать выходы в соответствующие таблицы. Сравните эти две таблицы, и у вас есть это.

Это не совсем научный вопрос, который, я думаю, был вопросом OP, но я не знаю формального метода для доказательства эквивалентности.

1

Возможно, вы могли бы нарисовать (вручную) свой запрос и результаты с помощью Venn Diagrams и посмотреть, производят ли они одну и ту же диаграмму. Диаграммы Венна хороши для представления наборов данных, а SQL-запросы работают с наборами данных. Выставление диаграммы Венна может помочь вам визуализировать, если 2 запроса функционально эквивалентны.

2

Это довольно легко сделать.

Давайте предположим, что ваши запросы называются а и б

минус б

должно дать вам пустое множество. Если это не так. то запросы возвращают разные наборы, а набор результатов показывает вам разные строки.

затем сделать

б минус

, что должно дать вам пустое множество. Если это так, то запросы возвращают одни и те же множества. , если он не пуст, в некоторых случаях запросы разные, а в результирующем наборе отображаются строки, которые отличаются друг от друга.

1

Это сделает трюк. Если этот запрос возвращает нулевые строки, два запроса возвращают одинаковые результаты. В качестве бонуса он работает как один запрос, поэтому вам не нужно беспокоиться о настройке уровня изоляции, чтобы данные не менялись между двумя запросами.

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

Вот удобный скрипт, чтобы сделать это:

#!/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

ОСТОРОЖНЫ! Функциональная «эквивалентность» часто основана на данных, и вы можете «доказать» эквивалентность двух запросов, сравнивая результаты для многих случаев и по-прежнему ошибаться, как только данные будут меняться определенным образом.

Например:

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

Вы должны действительно проверить Cosette: Он проверяет (с доказательством), если 2 SQL запроса являются эквивалентными и встречные примеры, когда не эквивалентны. Это единственный способ быть абсолютно уверенным, ну почти;) Вы можете даже выбросить 2 запроса на свой сайт и проверить (формальную) эквивалентность сразу.

Ссылка на Cosette: http://cosette.cs.washington.edu/

Ссылка на статью, которая дает хорошее объяснение того, как работает Cosette: https://medium.com/@uwdb/introducing-cosette-527898504bd6

Если все, что вы хотите, это просто быстрый практический исправить, вы также можете проверить этот StackOverflow ответ : [sql - check if two select's are equal]

Смежные вопросы