Подзапросы и возможность внешней ссылки с коррелированными подзапросами

Я обновляю свой SQL.
Я читал о подзапросах и возможности ссылаться извне с коррелированными подзапросами.
Пример:

SELECT *  
FROM ORDERS O  
WHERE 'ROAD BIKE' =  
(SELECT DESCRIPTION FROM PART P WHERE P.PARTNUM = O.PARTNUM)  

Это эквивалентно соединению:

SELECT O.ORDEREDON, O.NAME,  
O.PARTNUM, O.QUANTITY, O.REMARKS  
FROM ORDERS O, PART P  
WHERE P.PARTNUM = O.PARTNUM AND P.DESCRIPTION = 'ROAD BIKE'  

Моя проблема в том, что я не получил первую форму и когда/почему мы ее используем. Когда полезны внешние ссылочные запросы?


person Cratylus    schedule 16.02.2013    source источник
comment
Я думаю, вы могли бы привести аргумент, что первое яснее.   -  person Explosion Pills    schedule 17.02.2013
comment
Вы также можете привести аргумент, что первый намного медленнее до SQL 6.0.   -  person Achrome    schedule 17.02.2013
comment
@ExplosionPills: Почему понятнее? Я даже не понимаю, как работают эти запросы и где их применять.   -  person Cratylus    schedule 17.02.2013


Ответы (3)


Заказы имеют ссылку на номер детали, поэтому таблица Orders имеет внешний ключ для номеров деталей.

Нам нужны все заказы, в которых номер детали указан как «Шоссейный велосипед».

Первая форма сначала выполняет подзапрос к каждой записи, чтобы проверить, является ли O.PARTNUM номером детали для "Road Bike".

Если подумать, то основной запрос проходит через каждую запись в таблице Orders. Для каждой записи он выполняет подзапрос, где в запросе используется его поле PARTNUM. Итак, если вы используете PARTNUM записи Orders в подзапросе, выберите, чтобы найти запись в таблице PART с этим PARTNUM, и выберите поле DESCRIPTION. Затем предложение where основного запроса проверяет, соответствует ли «Дорожный велосипед» DESCRIPTION, возвращаемому из подзапроса.

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

SELECT *  
FROM ORDERS O  
WHERE O.PARTNUM =  
(SELECT P.PARTNUM FROM PART P WHERE DESCRIPTION = 'ROAD BIKE')

Это не коррелированный запрос. База данных может выполнить подзапрос один раз, получить PARTNUM для записи с "ROAD BIKE" в качестве DESCRIPTION, а затем выполнить основной запрос с условием WHERE O.PARTNUM равно результату подзапроса.

person Marlin Pierce    schedule 16.02.2013
comment
Есть ли вариант использования, когда коррелированный подзапрос является единственным выходом? решает какую-то конкретную задачу? - person Cratylus; 17.02.2013
comment
Это некоторые коррелированные подзапросы, для которых нет другого эквивалентного SQL без коррелированного подзапроса. Тогда это неизбежно. - person Marlin Pierce; 17.02.2013
comment
Я имею в виду, что это не SQL, который можно было бы писать каждый день, скажем. Это крайний случай? - person Cratylus; 17.02.2013
comment
Очень редко вы могли столкнуться с абсолютной необходимостью написать подзапрос. Я могу придумать пару сценариев, но не более того. - person Achrome; 17.02.2013
comment
Большинство запросов в основном выбирают * из одной таблицы. Может 90%. Неинтересные SQL-запросы. Среди интересных запросов коррелированные запросы, как предотвратимые, так и неизбежные, являются известными ловушками, достаточно распространенными, чтобы о них говорить. - person Marlin Pierce; 17.02.2013

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

Коррелированные подзапросы выполняют внутренний запрос один раз для каждой строки во внешней таблице. Это приводит к ужасной производительности (внешняя таблица из 1 миллиона строк приведет к тому, что внутренний запрос будет выполнен 1 миллион раз!)

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

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

person Bohemian♦    schedule 16.02.2013
comment
1) Есть ли вариант использования, когда коррелированный подзапрос является единственным выходом? 2) Также есть ли разница в производительности между соединениями и коррелированными подзапросами или соединениями и подзапросами в целом? - person Cratylus; 17.02.2013
comment
Коррелированные подзапросы вернутся в MySQL 6.0. - person Achrome; 17.02.2013
comment
@AshwinMukhija: Не знаю, что вы имеете в виду. Я запускаю первую форму (которая является коррелированным подзапросом) в MySQL, и она работает. - person Cratylus; 17.02.2013
comment
О, я имею в виду, что коррелированные подзапросы теперь работают ужасно. Но с MySQL 6.0 интерпретатор будет автоматически преобразовывать коррелированный подзапрос в объединение везде, где это возможно. - person Achrome; 17.02.2013

Сценарий, в котором подзапрос может быть уместным, выглядит примерно так:

select some fields
from some tables
where some conditions are met  
and somefield = (select min(something) from etc)

Однако я не знаю, является ли это коррелированным подзапросом. Семантика не моя сильная сторона.

person Dan Bracuk    schedule 16.02.2013
comment
Коррелированный подзапрос — это когда ваш подзапрос ссылается на часть вашего внешнего запроса. В моем примере обратите внимание на WHERE P.PARTNUM = O.PARTNUM. Таблица O определена вне. - person Cratylus; 17.02.2013