SQL - запрос внутри NOT IN занимает больше времени, чем полный запрос? - PullRequest
5 голосов
/ 05 января 2011

Я использую NOT IN внутри своего SQL-запроса.

Например:

select columnA 
from table1
where columnA not in (
select columnB
from table2)

Как это возможно, что эта часть запроса

select columnB
from table2

требуется 30 секунд для завершения, но весь запрос выше занимает 0,1 секунды для завершения ??Если полный запрос не займет 30 секунд +?

Кстати, оба запроса вернут действительные результаты.

Спасибо!

Ответы на комментарии

Это потому, что второй запрос на самом деле не завершен, а только возвратил первые строки 'x' (из очень большой таблицы?)

Нет, запросзавершается через 30 секунд, а не во многих возвращаемых строках (например, 50).

Но @Aleksandar задумался, почему вопрос, связанный с убийцей производительности, был таким быстрым.моя точка зрения точно

Кроме того, сколько времени требуется для выбора отдельного столбца B из таблицы2 для выполнения?

на самом деле исходный запрос "выбрать отличный ...

Ответы [ 6 ]

4 голосов
/ 05 января 2011

Кажется, вы думаете, что ваш основной запрос подразумевает следующие шаги:

(1)  Run the subquery
(2)  Check each row in table1 against the result set from the subquery.

Таким образом, вы считаете, что отдельный подзапрос должен занимать меньше времени, чем весь запрос.

Но SQL не является процедурным языком, и структура запроса не обязательно подразумевает шаги, которые будут выполнены для выполнения запроса.

Как ответил Гуффа, оптимизатор придумает (как он считает) оптимальный план для выполнения каждого запроса. Эти планы выполнения не всегда очевидны при взгляде на запрос, и в некоторых случаях они могут быть довольно нелогичными.

Я думаю, что в этом случае наиболее вероятно, что оптимизатор придумал более быстрый метод проверки существования значения в таблице2, чем простой запрос всех таблиц2 одновременно. Это может быть преобразование, показанное Гуффой (хотя это все еще не говорит вам точный используемый план выполнения).

Я бы предположил, что table1 имеет значительно меньше строк, чем table2, и индекс существует для table2.columnB. Поэтому все, что нужно сделать, - это извлечь строки из таблицы table1, а затем проверить индекс для каждого из этих значений, чтобы проверить их существование. Но это только одна возможность.

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

4 голосов
/ 05 января 2011

Это потому, что оптимизатор запросов превращает запрос в нечто совершенно иное. Фактический запрос должен совпадать с запросом, подобным следующему:

select columnA 
from table1
left join table2 on ColumnA = ColumnB
where ColumnB is null

Если база данных может использовать индексы для объединения таблиц, возможно, ей не нужно запрашивать всю таблицу2 или даже касаться самой таблицы.

2 голосов
/ 05 января 2011

Драматическое сравнение, скажем так ...

select columnB
from table2

... имеет миллиард строк (30 секунд), многие данные передаются по проводам и представляются пользователю.

Иэто ...

select columnA 
from table1

... имеет только одну строку.

СУБД не будет выполнять глупую работу по переносу данных таблицы 2 с сервера на клиент, если вы этого не сделаетенамерены отобразить данные таблицы2.Таким образом, при тестировании присутствия данных не будет сильно задействована пропускная способность сети или операции ввода-вывода, все это происходит на сервере, единственная вещь, которая будет передаваться с сервера на клиент, - это только одна строка таблицы 1.

select columnA 
from table1
where columnA not in (
select columnB
from table2)

И все должно быть особенно быстро, если у ваших columnA и columnB есть индекс

Вещи, которые замедляют работу базы данных, имеют два аспекта: во-первых, это когда вы переносите слишком много данных с сервера на клиент,во-вторых, когда у вас нет индекса для соответствующих полей

0 голосов
/ 05 января 2011

просто собираюсь войти, убедитесь, что вы знаете разницу между NOT In и NOT EXISTS .

Если значение «columnA» равно NULL, оно не будет возвращено через решение NOT IN, которое вы просматриваете, но уже представленные ЛЕВЫЕ примеры антисоединений будут вести себя как NOT EXISTS.

Также убедитесь, что TOAD / SQL Developer не «показывает только первые 50», которые им нравится делать (выполните select count (*) из таблицы1, чтобы увидеть, действительно ли 50 является результатом запроса).

сделайте EXPLAIN PLAN для запроса и посмотрите, выделяет ли он что-либо, что выглядит вопиющим - проверьте ваши индексы, а также посмотрите, допускают ли NULLS столбцы - причиной может быть отсутствие индексов, но полное сканирование таблицы из NULLS вызывающий кошмар).

0 голосов
/ 05 января 2011

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

0 голосов
/ 05 января 2011

НЕ является убийцей производительности.

На некотором механизме SQL сначала выполняет вход (...) во временную таблицу, повторно выполняет запрос, делая НЕ для данных во временной таблице.

Если вы можете, вы должны использовать только IN!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...