2015-08-07 5 views
5

У меня проблема с производительностью.Multiples INNER JOIN слишком медленный SQL SERVER

Я создал таблицу, которая получает данные из файла, я делаю BULK INSERT. Затем я делаю SELECT с несколькими INNER JOIN s (11 внутренних соединений) для вставки в другую таблицу с нужными данными.

Когда я запускаю этот SELECT, он занимает слишком много времени (более часа), а затем я его останавливаю. Моим решением было разбить этот запрос на 3, создав таблицы @temp. К моему удивлению, это занимает 3 минуты. Это то, что я пытаюсь понять, ПОЧЕМУ, разбивая мой запрос на 3, был FASTER, чем один оператор select. Вот мой запрос:

SELECT t1.ReturnINT, t1.ReturnBIT, t2.ReturnINT, t3.ReturnINT, t5.ReturnINT, t1.ReturnDateTime 
FROM t1 
INNER JOIN t2 
    ON t2.my_column_varchar = t1.my_column_varchar 
INNER JOIN t3 
    ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID 
INNER JOIN t4 
    ON t4.my_column_varchar = t1.my_column_varchar 
INNER JOIN t5 
    ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int 
INNER JOIN t6 
    ON t6.my_column_int = t5.my_column_int AND t6.my_column_int = t2.my_column_int 
INNER JOIN t7 
    ON t7.my_column_int = t6.my_column_int 
INNER JOIN t8 
    ON t8.my_column_int = t3.my_column_int AND t8.my_column_datetime = t1.my_column_datetime 
INNER JOIN t9 
    ON t9.my_column_int = t3.my_column_int AND t8.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2 
INNER JOIN t10 
    ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = t6.my_column_int 
INNER JOIN t11 
    ON t11.my_column_int = t9.my_column_int AND t8.my_column_datetime = t11.my_column_datetime 

---- EDITED ----

Существует НЕТ, где положение, мой запрос точно так, как я ставлю здесь.

Вот мои сломанные запросы, я забыл положить их сюда. Он работает через 3 минуты.

DECLARE @temp TABLE (
    <Some_columns> 
) 
INSERT INTO @temp 
    SELECT <My_Linked_Columns> 
    FROM t1 
    INNER JOIN t2 
     ON t2.my_column_varchar = t1.my_column_varchar 
    INNER JOIN t3 
     ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID 
    INNER JOIN t4 
     ON t4.my_column_varchar = t1.my_column_varchar 
    INNER JOIN t5 
     ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int 


DECLARE @temp2 TABLE(
    <Some_Columns> 
) 
INSERT INTO @temp2 
    SELECT <More_Linked_Columns> 
    FROM @temp as temp 
    INNER JOIN t6 
     ON t6.my_column_int = temp.my_column_int AND t6.my_column_int = temp.my_column_int 
    INNER JOIN t7 
     ON t7.my_column_int = t6.my_column_int 
    INNER JOIN t8 
     ON t8.my_column_int = temp.my_column_int AND t8.my_column_datetime = temp.my_column_datetime 


DECLARE @temp3 TABLE(
    <Some_Columns> 
) 
INSERT INTO @temp3 
    SELECT <More_Linked_Columns> 
    FROM @temp2 AS temp2 
    INNER JOIN t9 
     ON t9.my_column_int = temp2.my_column_int AND temp2.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2 
    INNER JOIN t10 
     ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = temp2.my_column_int 
    INNER JOIN t11 
     ON t11.my_column_int = t9.my_column_int AND temp2.my_column_datetime = t11.my_column_datetime 


SELECT <All_Final_Columns> 
FROM @temp3 

---- EDITED 3 ----

Изучение больше вещей, я обнаружил проблему в плане выполнения. У меня есть вложенный цикл, который оценивает 1 строку, но на самом деле возвращает строки 1.204.014. Я думаю, проблема именно здесь, но я не нашел, как решить эту проблему, не нарушая мой запрос в 3-х частях (Теперь я знаю, почему это нарушение быстрее хехехе)

+2

Это может быть любое количество вещей. Это может быть индексирование, возможно, у вас есть предикаты nonSARGable, если есть предложение where, список можно продолжать и продолжать. Без каких-либо конкретных подробностей мало кто может сделать, но догадываться о том, что делает это медленным. –

+1

Это уменьшает выбор Оптимизатора для выбора порядка соединения и типа соединения –

ответ

2

Наиболее распространенные причины:

Причина 1: Когда две таблицы, имеющие п и т строк, участвующих в INNER JOIN имеют отношения многие ко многим, то INNER JOIN может около CROSS JOIN и может производить набор результатов с более чем MAX (п, т) строк, теоретически NXM строк возможны.

Теперь представьте себе множество таких таблиц в INNER JOIN.

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

Это может быть причиной того, почему временные таблицы могут вам помочь.

Причина 2: У вас нет INDEX, построенного на столбцах, на которые вы соединяете столы.

Причина: Есть ли у вас функции в категории WHERE?

1

В общем, вы хотите, чтобы оптимизатор запросов присоединился к таблицам таким образом, чтобы максимально ограничить набор результатов. Если у вас есть таблица A с 1 миллионом строк, таблица B с 1 миллионом строк и таблица C с 10 строками, вы хотите сначала выполнить внутреннее соединение из таблицы C в A или B, это даст вам максимум 10 записей (при условии, что совпадение 1: 1), чтобы затем присоединиться к последней таблице. Если вы сначала присоединились к A до B, вы бы присоединились на все 1 миллион строк от каждого, что займет немного больше времени.

Обычно оптимизатор запросов «достаточно хорош» при выборе порядка соединения, но в вашем случае это не так.Лучший метод, который я видел для форсирования заказа на соединение, был продемонстрирован Adam Mechanic in a blog post here. Он включает использование предложения TOP для таблиц, с которых вы хотите начать соединение. Затем оптимизатор запросов получит набор результатов из этих таблиц, и вы действительно сможете ограничить общее количество строк и увеличить производительность запросов. Я использую этот метод, когда это возможно.

0

С правильным индексом или индексами исходный запрос должен выполняться очень быстро (дольше, чем одна секунда, если вы размещаете данные). Не используйте временные таблицы в качестве взлома для того, чтобы не было возможности найти разумный запрос.

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