Индекс поиска слияния - PullRequest
11 голосов
/ 31 мая 2011

У меня есть таблица [MyTable] со столбцом [MyColumn] NVarchar (50).У меня есть некластеризованный индекс для этого столбца, теперь при выполнении следующих двух запросов:

SELECT  1
FROM    [MyTable] M
WHERE   M.[MyColumn] = @MyColumn

SELECT  1
FROM    [MyTable] M
WHERE   M.[MyColumn] = COALESCE(@MyColumn, M.[MyColumn] )   

Я заметил, что первый запрос использует Index Seek (NonClustered) , а второй использует Сканирование индекса (не кластеризовано) .Могу ли я узнать, как я буду использовать индексный поиск с coalesce или isnull?

Ответы [ 5 ]

2 голосов
/ 31 мая 2011

Могу ли я знать, как я буду использовать Индекс поиска слияния или isnull?

Возможно, не ответ на ваш вопрос, но у вас может быть два разных запроса. Один для случая, когда @MyColumn is null и один для случая, когда вы хотите использовать @MyColumn в предложении where.

IF @MyColumn IS NULL
BEGIN
  SELECT  1
  FROM    [MyTable] M
END  
ELSE
BEGIN
  SELECT  1
  FROM    [MyTable] M
  WHERE   M.[MyColumn] = @MyColumn
END  
0 голосов
/ 31 мая 2011

В запросе с предложением coalesce оптимизатор знает, что «MyColumn» - это диапазон значений, поэтому он решит использовать сканирование индекса. Единственный метод, который использует поиск, когда передается ненулевая переменная, - это кодирование двух сохраненных процедур и вызов подходящего с помощью логического тестирования переменной.

Если у вас такая простая ситуация, как в вашем примере, и вы хотите использовать поиск по индексу, когда переменная NOT NULL, вам следует кодировать запрос следующим образом:

If @MyColumn is NULL
Begin
    EXEC MyStoredProcWithMyColumn=Mycolumn
END
ELSE
Begin
    EXEC MyStoredProcWithMyColumn=Variable @MyColumn
END

после создания двух хранимых процедур, одна из которых возвращает данные, используя предложение where с переменной, а другая - с использованием where для столбца, равного самой себе.

0 голосов
/ 31 мая 2011

Полагаю, вы будете использовать этот запрос в более сложном, возможно, с EXISTS:

EXISTS 
( SELECT  1
  FROM    [MyTable] M
  WHERE   M.[MyColumn] = COALESCE(@MyColumn, M.[MyColumn] )
)

Попробуйте вместо этого:

EXISTS 
( SELECT  1
  FROM    [MyTable] M
  WHERE   M.[MyColumn] = @MyColumn
)
OR EXISTS
( SELECT  1
  FROM    [MyTable] M
  WHERE   @MyColumn IS NULL
)

Или этот:

CASE WHEN @MyColumn IS NULL
     THEN 1
     ELSE 
        ( SELECT  1
          FROM    [MyTable] M
          WHERE   M.[MyColumn] = @MyColumn
        )
END
0 голосов
/ 31 мая 2011

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

То, что вы МОЖЕТЕ сделать, это создать вычисляемый столбец для результата вашей функции и индексировать этот столбец .

На самом деле нет более красивого способа получить поиск.

EDIT:

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

РЕДАКТИРОВАТЬ 2:

Вместо текущей логики попробуйте что-то вроде:

...
WHERE (M.[MyColumn] = @MyColumn 
       OR @MyColumn IS NULL)
0 голосов
/ 31 мая 2011

Использование таких функций, как COALESCE или ISNULL в предложении where, запрашивает у сервера поиск результатов этих функций, которые неизвестны до тех пор, пока они не будут выполнены для каждой строки в результирующем наборе., поэтому у него нет возможности использовать индекс.

Чтобы в полной мере использовать индекс, не используйте функции в предложении WHERE, измените его со стандартными условиями, например WHERE MyColumn = @MyColumn OR @MyColumn IS NULL

...