Каким должен быть порядок фильтров в запросе, чтобы оптимизировать запросы для использования индексации - PullRequest
3 голосов
/ 23 января 2011

У меня мало сомнений.Я слышал от некоторых моих коллег, что если мы создали составной индекс Nonclustured для следующей таблицы, порядок всех фильтров должен быть в порядке столбца Indexed, а затем Filter.

MyTable (T1, T2,T3, T4, T5)
Индекс без привязки (T1, T2) в порядке T1, затем T2

Вопросы

  1. Какой из запросов работает быстрее?

  2. Влияет ли порядок индексации столбца на производительность?

  3. Должны ли индексированные столбцы идти впереди для оптимизации запросов?

  4. Каков порядок обработки запроса.Какой фильтр используется первым при обработке запроса?Он начинается с последнего фильтра и продолжается до первого фильтра?

Запрос 1

Select * from MyTable WHERE T1=1 AND T2=2 AND T3=1 
--(Indexing will be used) Fastest as T3 has been included after indexed columns

Запрос 2

Select * from MyTable WHERE T2=1 AND T1=2 AND T3=1
--(No Indexing will be used)

Запрос 3

Select * from MyTable WHERE T3=1 AND T1=1 AND T2=2
--(Indexing will be used) slower than Query 1 as indexed columns included afterwards

Запрос 4

Select * from MyTable WHERE T3=1 AND T2=1 AND T1=2
--(No Indexing will be used) slower than Query 2 as indexed columns occurs after non indexed column condition

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

Запрос 5

Select * from MyTable WHERE T3=1 AND T2=1

Запрос 6

Select * from MyTable WHERE T3=1 AND T1=1 

Запрос 7

Select * from MyTable WHERE T3=1 AND T2=1 OR T1=2

Запрос 8

Что означает следующий порядок при создании индекса SSMS, т.е. какой фильтр должен стоять первым?

alt text

Когда я пытался перетасовать порядок столбцов, показанных в индексных столбцах.Я видел Поиск закладок увеличивался и использовалось сканирование индекса Clustured.Но когда я использую тот же порядок, как показано на рисунке.Затем был удален поиск по закладкам, а также поиск по индексу.Итак, я вижу, что порядок столбцов в индексе играет здесь важную роль, но не мог понять, как это сделать.

Ответы [ 3 ]

5 голосов
/ 23 января 2011

Порядок предикатов в запросе не имеет значения!

Обычная аналогия при рассмотрении порядка столбцов в составных индексах - это телефонная книга.Это заказано (фамилия, имя).Это упрощает поиск по фамилии, но не помогает искать номера по имени.

Если у вас есть индекс на (T1, T2), его можно использовать для эффективного ответа

Select * from MyTable WHERE T1=2

или

Select * from MyTable WHERE T2=1 AND T1=2

Но не для эффективного ответа

Select * from MyTable WHERE T2=1

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

Пример скрипта согласно комментариям

CREATE TABLE MyTable  (
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
T1 INT NOT NULL,
T2 INT NOT NULL,
Filler CHAR(8000) NOT NULL /*Just to make sure that the table is very wide!*/);

CREATE NONCLUSTERED INDEX IX ON MyTable (T1,T2);

   WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
 INSERT INTO MyTable 
 SELECT N, N-1,''
   FROM cteTally
  WHERE N <= 1000;

 SET STATISTICS IO ON
 Select * from MyTable  WHERE T2=1
 /*
 Table 'MyTable'. Scan count 1, logical reads 9, physical reads 0, 
 read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 */

 /*Force a clustered index scan just to compare...*/
 Select * from MyTable   WITH( INDEX (1) ) WHERE T2=1 
/*
Table 'MyTable'. Scan count 1, logical reads 1005, physical reads 0, 
read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.*/

Plans

2 голосов
/ 23 января 2011

Q8 (без нумерации) Что означает следующий порядок при создании индекса SSMS, т. Е. Какой фильтр должен стоять первым?

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

В 1. Какой из запросов работает быстрее?

Порядок предложений OR в запросе does not matter. SQL Server проверит их все и использует любой индекс, чтобы все ваши первые 4 запроса использовали один и тот же план, поэтому same performance.

Q 2. Влияет ли порядок индексированного столбца на производительность?

Не в запросе, но это происходит, если вы создаете составной индекс. Индекс на (A, B) будет полезен для запросов, которые включают A, не может (обычно) использоваться для запросов, которые включают только B. Индексируйте по (B, A) сначала группы по B, затем по A на страницах индекса, поэтому запрос, где A = 1, не может его использовать. Существуют некоторые особые случаи, например, когда запросу нужны только A и B в предложениях SELECT / JOIN / WHERE, поэтому он все равно может использовать индекс для (B, A), потому что его легче собрать, чем кластерный ключ.

В 3. Должны ли индексированные столбцы быть первыми для оптимизации запросов?

То же, что и ответ на 1.

Q 4. Каков порядок обработки запроса. Какой фильтр используется первым при обработке запроса? Он начинается с последнего фильтра и продолжается до первого фильтра?

То же, что и ответ на 1.

Для отредактированных вопросов 5-7

Q7 единственный, кто отличается. Другие включают прямое И, поэтому условие не зависит от порядка полей. Последний действительно имеет две группы условий (A и B) или (C), поэтому будет использоваться индекс как (A, B), так и / или индекс по (C), если они достаточно избирательны (отфильтрует данные в достаточно меньшее подмножество). Если оба индекса существуют, два результирующих потока могут быть собраны и сравнены (хеш / объединение) для получения окончательного результата.

1 голос
/ 23 января 2011

Помимо всех других замечаний, если вы всегда используете SELECT * FROM MyTable в своих запросах, чаще всего оптимизатор запросов SQL Server будет предпочитать вообще игнорировать любые индексы и выполнять сканирование таблицы - даже если индекс есть.

Почему?

Если вы попросите SQL Server вернуть все столбцы в вашей таблице, в конечном итоге ему все равно придется читать фактическую страницу данных для каждой строки. Поиск строк в индексе, а затем поиск закладок на реальных страницах данных - довольно дорогая операция, поэтому, если вы не очень избирательны с предложением WHERE (выбирая только несколько процентов данных) затем, скорее всего, SQL Server выполнит полное сканирование таблицы, чтобы получить все необходимые данные.

Если вы можете, всегда используйте SELECT (list of columns) FROM Mytable и сохраняйте этот список столбцов как можно меньше. В этом случае вы можете иметь индекс, в котором уже есть большинство этих столбцов, и затем вы можете добавить эти дополнительные два или три столбца, так как включает столбцы в свой индекс, чтобы сделать это индекс покрытия . Это позволило бы SQL Server возвращать запрошенные вами значения, просто сканируя некластеризованный индекс - вместо того, чтобы выполнять дорогостоящий поиск закладок или полное сканирование таблицы.

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