Подтвердить что ты не робот

Проверка эквивалентности запросов SQL

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


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

4b9b3361

Ответ 1

Лучшее, что вы можете сделать, это сравнить 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);

Ответ 2

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

Ответ 3

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

Предположим, что ваши запросы называются a и b

а минус б

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

то do

б минус а

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

Ответ 4

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

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

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

Если все, что вам нужно, это просто быстрое практическое решение, вы также можете проверить этот ответ stackoverflow: [sql - проверьте, равны ли два выбора]

Ответ 5

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

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

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

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

SELECT /*+RULE*/ FROM yourtable

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

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

Ответ 6

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

Ответ 7

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

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

Вот вам удобная оболочка script:

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

Ответ 8

Нет.

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

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

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

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

Ответ 9

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

Например:

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.**