Специальный оператор EXISTS используется для проверки результата работы подзапроса. Это позволяет выполнить внешний запрос, но только тогда, когда проверка EXISTS возвращает значение "истина".
Шесть одних и полдюжины других
Как и с операторами сравнения, при работе с операторами IN для инвертирования полученных результатов используется ключевое слово NOT, благодаря чему определяются записи, которые были получены подзапросом и не вошли в результирующий набор. Для того чтобы показать это, перепишем предыдущий запрос
SELECT cname FROM clients WHERE cid IN (SELECT cid FROM branches WHERE bid IN (SELECT bid FROM branches_services AS bs, services AS s WHERE bs.sid = s.sid GROUP BY bid HAVING SUM(sfee) >= 2000));
в следующий эквивалент, возвращающий аналогичный результирующий набор:
SELECT cname FROM clients WHERE cid IN (SELECT cid FROM branches WHERE bid NOT IN (SELECT bid FROM branches_services AS bs, service AS s WHERE bs.sid = s.sid GROUP BY bid HAVING SUM(sfee) < 2000));
Вот простенький пример: Листинг 11.25.
mysql> SELECT * FROM clients WHERE EXISTS (SELECT bid FROM branches_services GROUP BY bid HAVING COUNT(sid) >= 5);
Empty set (0.17 sec)
В этом случае из-за того, что подзапрос возвращает пустой результирующий набор - филиалы, которые пользуют пятью и более услугами, не зафиксированы - проверка EXISTS возвращает значение "ложь", и, следовательно, внешний запрос не выполняется.
А теперь посмотрим, что произойдет, если предыдущий подзапрос немного видоизменить, чтобы он возвратил хоть какой-то результат.
В этом случае из-за того, что некоторые филиалы пользуются четырьмя и более услугами, внутренний запрос возвратит результирующий набор, содержащий как минимум одну строку, тест EXISTS возвратит значение "1101", а это значит, что внешний запрос будет выполнен.
Необходимо заметить, что результирующий набор этого внешнего запроса не представляет собой перечень заказчиков, пользующихся не менее чем четырьмя услугами. Скорее всего, это можно назвать списком всех заказчиков, который возвращается только благодаря тому, что внутренний запрос сработал и выдал какой-то (неважно какой) результирующий набор. В предыдущем примере результирующий набор, полученный внутренним запросом, сам по себе ничего не означает. Совершенно аналогичный результат можно получить, выполнив следующий запрос.
Оператор EXISTS чаще всего используется в конструкциях, которые SQL-гуру называют внешними ссылками.
Внешние ссылки
Чаще всего, если подзапрос дает один и тот же результат при каждом запуске, имеет смысл запустить запрос один раз и использовать один и тот же результирующий набор при тестировании каждой записи, сгенерированной в главном запросе. Однако иногда возможны ситуации, когда подзапрос использует поле из главного запроса в своем предложении. Такая ссылка из подзапроса на поле из внешнего запроса называется внешней ссылкой, и такой подзапрос называется связанным подзапросом, т.к. он связан с результирующим набором одного включающего его запросы (более).
Если в подзапросе появляется внешняя ссылка, MySQL запускает подзапрос для каждой записи, полученной для внешнего запроса, а значит, подзапрос срабатывает столько раз, сколько записей будет получено в результирующем наборе внешнего запроса. В таком случае оператор EXISTS оказывается очень полезным для отброса определенных записей из окончательного результирующего набора.
Этот момент поможет прояснить пример. Рассмотрим предыдущий пример, но уже с использованием внешней ссылки для того, чтобы сделать результирующий набор более полезным.
Себе дороже
Внешние ссылки помогают понять одну интересную проблему оптимизации запросов. В случае применения внешней ссылки, MySQL должен запустить внутреннюю ссылку для каждой записи, полученной внешним запросом, т.к. во внешних ссылках используется результирующий набор внешнего запроса. Это приводит к увеличению нагрузки на сервер, а значит, к деградации производительности сервера. По этой причине следует избегать использования внешних ссылок по мере возможности, применяя другие способы объединения данных (например, это может быть самообъединение или объединение UNION), благодаря которым обычно уменьшаются накладные расходы по времени выполнения и использованию ресурсов.
Рассмотрим связанный подзапрос из предыдущего примера:
SELECT bid, bdesc FROM branches WHERE EXISTS (SELECT bid FROM branches_services WHERE branches.bid = branches_services.bid
GROUP BY bid HAVING COUNT (sid) >= 4);
и вот такое объединение, которое дает совершенно аналогичный результат, но значительно быстрее:
SELECT branches.bid, branches.bdesc FROM branches_services, branches WHERE branches.bid = branches_services.bid GROUP BY bid HAVING
COUNT (sid) >= 4;
И действительно, даже беглого взгляда достаточно, чтобы убедиться в том, что только один филиал воспользовался не менее чем четырьмя услугами (это филиал с идентификатором 1011).
В данном случае из-за того, что запрос имеет ссылку на внешний запрос, MySQL не может обработать внутренний запрос только один раз (как это обычно и происходит). Ему приходится запускать его вновь и вновь, по одному разу для каждой строки из внешней таблицы, заместить значение соответствующего поля из этой строки в подзапросе, а затем принять решение о включении этой внешней строки в окончательный результирующий набор исходя из того, возвращает ли соответствующий подзапрос результирующий набор. Очевидно, что это очень накладно с точки зрения производительности, поэтому применения внешних ссылок по мере возможности нужно избегать.
ТОП-10 популярных
Для работы с вещественными числами в MySQL предусмотрено три типа данных - это типы FLOAT, DOUBLE, DECIMAL. Числовой тип FLOAT...
БОЛЬШЕ БОЛЬШИХ LCD-мониторов
Процесс вытеснения с рынка мониторов с электронно-лучевой трубкой (CRT) продолжается. О смещении акцентов в пользу LCD-мониторов теперь заявляют даже те...
Процесс вытеснения с рынка мониторов с электронно-лучевой трубкой (CRT) продолжается. О смещении акцентов в пользу LCD-мониторов теперь заявляют даже те...
Больше больших LCD-мониторов
Процесс вытеснения с рынка мониторов с электронно-лучевой трубкой (CRT) продолжается. О смещении акцентов в пользу LCD-мониторов теперь заявляют даже те...
Процесс вытеснения с рынка мониторов с электронно-лучевой трубкой (CRT) продолжается. О смещении акцентов в пользу LCD-мониторов теперь заявляют даже те...
НОУТБУК с блестящим экраном
Eсли выпустившая ноутбук фирма предлагает его в качестве «замены настольному ПК», то это должно подразумевать под собой нечто большее, чем...
Eсли выпустившая ноутбук фирма предлагает его в качестве «замены настольному ПК», то это должно подразумевать под собой нечто большее, чем...
Иди и пиши. TravelMate C100
Планшетный компьютер платформы Tablet PC обязан в первую очередь быть легким, способным достаточно долго работать без подзарядки батарей. Эти требования...
Планшетный компьютер платформы Tablet PC обязан в первую очередь быть легким, способным достаточно долго работать без подзарядки батарей. Эти требования...
Магнито-оптический дисковод DynaMO
Cейчас, когда традиционные флоппи-дисководы на долгие годы замерли в своем развитии, поиск альтернативных носителей продолжается, и ситуация, казалось бы, разрешилась...
Cейчас, когда традиционные флоппи-дисководы на долгие годы замерли в своем развитии, поиск альтернативных носителей продолжается, и ситуация, казалось бы, разрешилась...
Компьютер для гурманов.«Эксимер ДМ»
Российская компания «Эксимер ДМ», известная как производитель настольных компьютеров, рабочих станций, серверов и ноутбуков, выступила техническим спонсором проведения торжеств, посвященных...
Российская компания «Эксимер ДМ», известная как производитель настольных компьютеров, рабочих станций, серверов и ноутбуков, выступила техническим спонсором проведения торжеств, посвященных...
Для длинных строк, т.е. строк длиннее 255 символов, в MySQL предусмотрены типы BLOB (Binary Large Object, большой двоичный объект) и...
В дополнение к календарным типам, предназначенным для хранения даты и времени отдельно, MySQL также поддерживает гибридные типы данных DATETIME и...
Вообще, к изменению настроек сервера прибегают очень редко. В MySQL программа заранее настроена так, чтобы соответствовать самым распространенным и основным...
Все о MySQL. Подзапросы и оператор exists
28-12-2009
<< Предыдущая статья | Следующая статья >> |
Все о MySQL. Типы подзапросов | Все о MySQL. Подзапросы и предложение from |