Запрос с подзапросом UNION занимает очень много времени - PullRequest
3 голосов
/ 08 августа 2011

У меня была странная проблема с некоторыми запросами, которые зависят от подзапроса.Они работают молниеносно, пока я не использую оператор UNION в подзапросе.Потом они бегают бесконечно, я дал через 10 минут.Сценарий, который я сейчас описываю, не тот, с которого я начинал, но я думаю, что он устраняет множество возможных проблем, но приводит к той же самой проблеме.Поэтому, несмотря на то, что это бессмысленный запрос, потерпите меня!

У меня есть таблица:

tblUser - 100,000 rows
tblFavourites - 200,000 rows

Если я выполню:

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser);  

… тогда он запускается впод секунду.Однако, если я изменю его так, чтобы подзапрос имел UNION, он будет работать не менее 10 минут (прежде чем я сдаюсь!)

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser UNION SELECT uid FROM tblUser);  

Бессмысленное изменение, но оно должно дать тот же результати я не понимаю, почему это должно занять больше времени?

Помещение подзапроса в представление и вызов этого вместо этого имеет тот же эффект.

Есть идеи, почему это будет?Я использую SQL Azure.


Проблема решена.Смотрите мой ответ ниже.


Ответы [ 6 ]

3 голосов
/ 08 августа 2011

UNION действительно делает DISTINCT для всех полей в объединенном наборе данных.Отфильтровывает дубликаты в окончательных результатах.

Индексируется ли Uid?Если нет, это может занять много времени в качестве обработчика запросов:

  • Создает первый набор результатов
  • Создает второй набор результатов
  • Отфильтровывает все дубликаты (что составляет половину записей) в хэш-таблице

Если дубликаты не являются проблемой (а использование IN означает, что их не будет), тогда используйте UNION ALL, который удаляет дорогую сортировку /Шаг фильтра.

2 голосов
/ 09 августа 2011

UNION обычно реализуются через временные таблицы в памяти.Вы по сути копируете свой tblUser два раза в память, БЕЗ ИНДЕКСА .Затем каждая строка в tblFavourites подвергается полному сканированию таблицы за 200 000 строк - это 200Kx200K = 40 миллиардов двухстрочных сканирований (потому что механизм запросов должен получить идентификатор из обеих строк таблицы)

Если ваш tblUser имеет индекс наuid (что определенно верно, потому что все таблицы в SQL Azure должны иметь кластеризованный индекс), то каждая строка в tblFavourites подвергается очень быстрому поиску индекса, что приводит к сканированию только 200Kxlog (100K) = 200Kx17 = 200K, каждая с 17 b-Сравнение древовидных индексов (что намного быстрее, чем чтение uid из строки на странице данных), поэтому оно должно составлять примерно 200Kx (3-4) или 1 миллион двухстрочных сканирований.Я полагаю, что более новые версии SQL-сервера могут также создавать временную хеш-таблицу, содержащую только uid, поэтому, по сути, она сводится к сканированию строк 200 КБ (при условии, что поиск в хеш-таблице является тривиальным).

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

По сути, запрос не в UNION выполняется примерно в 500 000 раз быстрее, если tblUser имеет индекс (должен быть в SQL Azure).

2 голосов
/ 08 августа 2011

UNION генерирует уникальные значения, поэтому механизм СУБД выполняет сортировку. В этом случае вы можете безопасно использовать UNION ALL.

1 голос
/ 09 августа 2011

Оказывается, проблема была в одном из индексов ... tblFavourites содержал два внешних ключа для первичного ключа (uid) в tblUser:

userId
otherUserId

оба столбца имели одинаковое определение и одинаковые индексы, но я обнаружил, что замена userId на otherUserId в исходном запросе решает проблему.

Я побежал:

ALTER INDEX ALL ON tblFavourites REBUILD

... и проблема ушла. Запрос теперь выполняется практически мгновенно.

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

Спасибо!

---- ОБНОВЛЕНИЕ

Выше было не совсем правильно. Он сделал исправление проблемы примерно за 20 минут, а затем вернулся. Я связывался со службой поддержки Microsoft в течение нескольких дней, и, похоже, проблема связана с tempDB. Они работают над решением в конце.

0 голосов
/ 09 марта 2016

Не имеет ли смысла перефразировать вопросы из

"UserIds, которых нет в объединенном списке всех идентификаторов, которые указаны в этой и / или этой таблице"

до

"UserIds, которых нет в этой таблице и которых нет в этой таблице либо

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser) 
AND   userID NOT IN (SELECT uid FROM tblUser);  
0 голосов
/ 23 июля 2013

Я только столкнулся с этой проблемой. Мне нужно пройти около 1 миллиона строк, и затем я понял, что некоторые из моих идентификаторов были в другой таблице, поэтому я объединился, чтобы получить ту же информацию в одном «НЕ СУЩЕСТВУЕТ». Я перешел от запроса, занявшего около 7 секунд, к обработке только 5000 строк через минуту или около того. Это, казалось, помогло. Я абсолютно ненавижу решение, но я перепробовал множество вещей, которые все заканчиваются одним и тем же крайне медленным планом выполнения. Этот получил мне то, что мне было нужно примерно через 18 секунд.

    DECLARE @PIDS TABLE ([PID] [INT] PRIMARY KEY)
    INSERT INTO @PIDS SELECT DISTINCT [ID] FROM [STAGE_TABLE] WITH(NOLOCK)
    INSERT INTO @PIDS SELECT DISTINCT [OTHERID] FROM [PRODUCTION_TABLE] WITH(NOLOCK)
        WHERE NOT EXISTS(SELECT [PID] FROM @PIDS WHERE [PID] = [OTHERID]

    SELECT (columns needed)
    FROM [ORDER_HEADER] [OH] WITH(NOLOCK)
    INNER JOIN @PIDS ON [OH].[SOME_ID] = [PID]

(И да, я пробовал "ГДЕ СУЩЕСТВУЕТ ..." для окончательного выбора ... внутреннее соединение было быстрее) Пожалуйста, позвольте мне еще раз сказать, я лично чувствую, что это действительно ужасно, но на самом деле я использую это соединение дважды в моем процессе, так что это сэкономит мне время в долгосрочной перспективе. Надеюсь, это поможет.

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