2010-12-06 4 views
4

Я использую MS SQL.Почему INTERSECT так медленно, как вложенный JOIN?

У меня есть огромный стол с индексами, чтобы сделать этот запрос быстро:

select userid from IncrementalStatistics where 
IncrementalStatisticsTypeID = 5 and 
IncrementalStatistics.AssociatedPlaceID = 47828 and 
IncrementalStatistics.Created > '12/2/2010 

Он возвращает менее чем за 1 секунду. В таблице есть миллиарды строк. Всего около 10000 результатов.

Я ожидал бы этот запрос также завершить в течение секунды:

select userid from IncrementalStatistics where 
IncrementalStatisticsTypeID = 5 and 
IncrementalStatistics.AssociatedPlaceID = 47828 and 
IncrementalStatistics.Created > '12/2/2010' 

intersect 

select userid from IncrementalStatistics where 
IncrementalStatisticsTypeID = 5 and 
IncrementalStatistics.AssociatedPlaceID = 40652 and 
IncrementalStatistics.Created > '12/2/2010' 

intersect 

select userid from IncrementalStatistics where 
IncrementalStatisticsTypeID = 5 and 
IncrementalStatistics.AssociatedPlaceID = 14403 and 
IncrementalStatistics.Created > '12/2/2010' 

Но это занимает секунд. Все индивидуальные запросы принимают < 1 секунду и возвращают около 10 тыс. Результатов.

Я бы ожидал, что SQL внутренне будет вызывать результаты из каждого из этих подзапросов в хэш-таблицу и выполнять хеш-пересечение - должен быть O (n). Результирующие множества достаточно велики, чтобы соответствовать памяти, поэтому я сомневаюсь, что это проблема ввода-вывода.

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

Почему INTERSECT так медленно? Уменьшает ли он до JOIN на ранней стадии обработки запросов?

+1

«Я сомневаюсь, что это проблема с io» -> что в плане объяснения говорят, что самая дорогая часть запроса? – Donnie

+0

Имеет ли MS SQL EXPLAIN или какой-либо способ просмотра плана запроса? Основываясь на ответах других людей, кажется, что реализация INTERSECT просто не умна ... –

+0

@Brendan - да, есть хорошая визуализация плана запроса. Этот запрос не казался достаточно тонким, чтобы прибегать к этому - я искал интуитивный аргумент. –

ответ

14

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

select userid 
    from IncrementalStatistics 
    where IncrementalStatisticsTypeID = 5 
     and IncrementalStatistics.AssociatedPlaceID in (47828,40652,14403) 
     and IncrementalStatistics.Created > '12/2/2010' 
    group by userid 
    having count(distinct IncrementalStatistics.AssociatedPlaceID) = 3 
+0

Чувак! Это было на тонну быстрее. Хотелось бы понять, почему? Кажется, что под капотом это действительно работает больше, чем выше. –

+1

@John Shedletsky: Это быстрее, потому что это один проход в таблице IncrementalStatistics по сравнению с 3 полностью отдельными запросами. –

+1

@ Joe: Я сомневаюсь, что причина в том, что это намного быстрее. INTERSECTING 2 набора из 10000 строк в памяти занимает менее 1 с на любом ПК, поэтому единственная причина, по которой запрос Джона может занимать больше 3 * 1 + 1 + 1 = 5, заключается в том, что механизм БД выбирает плохой план для его исходный запрос. –

 Смежные вопросы

  • Нет связанных вопросов^_^