2009-12-28 5 views
0

Мне нужно переписать запрос ниже, чтобы он был максимально эффективным. Любые предложения о том, как повысить производительность этого запроса? Я планирую установить столбцы t2_1 и t2_2, чтобы они не были обнуляемы и присваивали значение по умолчанию. Мне в основном интересно, если/как я могу изменить соединение, чтобы я мог перемещать разделы «WHERE ... IN ...» , Можно ли вместо этого использовать INNER JOIN?SQL Query re-write help

SELECT t1_1 FROM t1 
LEFT JOIN #t2 
ON t1.t1_3 = t2.t2_3 
WHERE ISNULL (t2.t2_1, 54) in (SELECT ParsedValue FROM tf_ToTable(@IDList1)) 
AND ISNULL (t2.t2_2, 97) IN (SELECT ParsedValue FROM tf_ToTable(@IDList2)) 
+1

Вы хотите иметь ISNULL (t2.t2_1, 54) и ISNULL (t2.t2_2, 97)? –

+0

Да, они были намеренно помещены туда. Как я уже упоминал в своем оригинальном посте, одна из первых вещей, которые я сделаю, - установить эти столбцы не null и их соответствующее значение по умолчанию. Мой главный вопрос: как я могу реструктурировать соединение, чтобы не было предложений WHERE IN. Вы можете игнорировать IS NULL с точки зрения настройки, если это вам поможет –

+1

Это не вопрос настройки. Это вопрос «IS NULL», сильно отличающийся от «ISNULL». Первый даже не будет разбираться. –

ответ

0

Я думаю, что запрос ниже, и изменение t2_1 и t2_2 до недействительных значений по умолчанию даст мне лучшую производительность, что вы, ребята, думаете? Разве это не позволило бы наилучшим образом использовать индексы?

SELECT t1_1 FROM t1 
LEFT JOIN #t2 ON t1.t1_3 = t2.t2_3 
INNER JOIN tf_ToTable(@IDList1) x_1 ON t2.t2_1 = x_1.ParsedValue 
INNER JOIN tf_ToTable(@IDList2) x_2 ON t2.t2_2 = x_2.ParsedValue 
0

Если вы t1.t1_3 не NULLABLE вы можете заменить левое соединение с внутренним соединением.

+0

Я не уверен, что это так. Рассмотрим следующее: в t1 есть запись, которая не имеет соответствующей записи в # t2. Это не null, это просто не соответствует. Использование вашей логики не позволяет исключить эту запись, если она будет включена в мой запрос? –

1
SELECT t1_1 
FROM #t2 
JOIN t1 
ON  t1.t1_3 = t2.t2_3 
WHERE t2.t2_1 = @IDList1 
     AND t2.t2_2 = @IDList2 
UNION ALL 
SELECT t1_1 
FROM t1 
WHERE @IDList1 = 54 
     AND @IDList2 = 97 
     AND t1_3 NOT IN 
     (
     SELECT t2_3 
     FROM #t2 
     ) 
+0

+1: Sargable и ISNULL (или COALESCE) означают, что индекс не может использоваться. –

0

Для начала, если ваши @ IDList1 и @ IDList2 являются строками, разделенными запятой, этот запрос не будет работать вообще. Если они являются переменными таблицы, вам нужно иметь SELECT из переменных таблицы для работы IN.

Кроме того, поскольку вы публикуете это как вопрос на открытом форуме, я собираюсь надеяться, что имена таблиц и имена столбцов были изменены для защиты невинных. Имена столбцов t1_1, t1_2 и т. Д. Довольно ужасны, поскольку соглашение об именах идет.

Я думаю, что сначала не понял вопрос. Вот два возможных решения:

SELECT 
    T1.t1_1 
FROM 
    T1 
LEFT JOIN #t2 T2 ON 
    T2.t2_3 = T1.t1_3 
WHERE 
    EXISTS 
    (
      SELECT 
       ParsedValue 
      FROM 
       tf_ToTable(@IDList1) 
      WHERE 
       ParsedValue = ISNULL(T2.t2_1, 54) 
    ) AND 
    EXISTS 
    (
      SELECT 
       ParsedValue 
      FROM 
       tf_ToTable(@IDList2) 
      WHERE 
       ParsedValue = ISNULL(T2.t2_2, 97) 
    ) 

Или, если это в конкретном случае ищет значения в строку с разделителями:

SELECT 
    T1.t1_1 
FROM 
    T1 
LEFT JOIN #t2 T2 ON 
    T2.t2_3 = T1.t1_3 
WHERE 
    ',' + @IDList1 + ',' LIKE '%,' + CAST(ISNULL(T2.t2_1, 54) AS VARCHAR) + ',%' AND 
    ',' + @IDList2 + ',' LIKE '%,' + CAST(ISNULL(T2.t2_2, 97) AS VARCHAR) + ',%' 

Этот последний запрос предполагает, что вы используете запятую как ваш разделитель и что в строке нет пробела. Вы можете использовать функцию REPLACE, чтобы избавиться от пробелов в строке, если вам нужно это сделать.

+0

Переменные idList представляют собой строки с запятой. В моем реальном примере у меня есть табличная функция, которая анализирует их в таблицах. Я добавил это изменение в свой пример. Имена были изменены для защиты невинных. Я согласен с тем, что t1_1 и t1_2 - это ужасные соглашения об именах. Извиняюсь, только первое, что я придумал. –

0

Вы должны использовать службы Reporting Services, чтобы иметь возможность предоставлять список, подобный этому, что означает, что он использует динамический SQL для его работы.

Если вы делаете t2_1 и t2_2 disallow NULL, тогда единственный раз, когда они будут NULL, будет из-за LEFT JOIN.

Кроме того, рассмотрите, является ли t2_3 уникальным, и является ли t1_3 внешним ключом в этой таблице и может ли t1_3 разрешать NULL. Но я предполагаю, что это не так, поскольку # t2 - временная таблица.

Если вы можете избавиться от инструкций ISNULL, то это поможет.

И, конечно же, не забудьте проиндексировать и подумайте о том, насколько велики ваши таблицы. Здесь так много факторов.

+0

Я думаю, что у меня есть все индексы, которые мне нужны, но из того, что я понимаю, используя предложение ISNULL или WHERE IN, эти индексы не будут использоваться правильно или даже вообще. Вот почему я пытаюсь понять, как переместить их в соединение. –

+0

Для этого вам не обязательно нужен JOIN. Оптимизатор запросов переводит предложение WHERE и предложение JOIN очень похоже. Вам нужно рассмотреть такие вещи, как «Что означает NULL?» И «Будет ли это лучше соответствовать UNION ALL?» И «Будут ли правильные индексы означать, что Merge Join будет выполнен вместо Hash/Loop Join? »,« Могу ли я избегать поиска? »И т. Д. –