2012-05-18 3 views
1

Я написал подзапрос, который идет как это:Как определить порядок столбцов для некластерного индекса

select top 1 A 
from my_table 
where B = some_joined_value_from_outer_query 
order by C desc 

Я хочу создать некластеризованную индекс, который позволит улучшить производительность в этой части.

3 вопросы здесь:

  1. Что было бы для индексированных столбцов правильный порядок?
  2. Также, если столбец A является индексированным столбцом или просто включен в индекс?
  3. Можно ли это переписать без подзапроса (обратите внимание на top 1 и order by desc) и может ли это повысить производительность?

РЕДАКТИРОВАТЬ: Вот запрос (часть процесса синхронизации данных):

SELECT ProductId, (
    SELECT Id 
    FROM [Order] 
    WHERE Number = (
     SELECT TOP 1 OrderNumber 
     FROM OtherDatabase..ReferenceTable 
     WHERE ProductNumber = Product.Number 
     ORDER BY [Date] DESC) 
    ) AS OrderId 
FROM Product 
+1

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

+0

Какова цель запроса? Чтобы найти все продукты в самом последнем порядке? Есть ли указатель в столбце '[date]'? –

+0

Мы хотим обновить ссылки в нашей собственной базе данных на основе этой справочной таблицы (которая работает с текстовыми номерами вместо идентификаторов). Столбец даты - столбец «C» в приведенном выше примере. У этого есть указатель, который Вы предложили. – Koen

ответ

4

()

CREATE NONCLUSTERED INDEX foo ON dbo.my_table(B, C DESC) INCLUDE (A); 

(Б)

Поскольку A не находится в WHERE или ORDER BY, это, вероятно, достаточно для того, чтобы быть в списке столбцов INCLUDE d, так как это просто «для езды» и необязательно быть частью ключа.

(C)

невозможно ответить без дополнительного контекста. Почему вы включаете только подзапрос, а затем спрашиваете о внешнем запросе, который мы не видим?

EDIT в отношении текущего разговора с @Quassnoi, я просто хотел, чтобы быстро показать, что направление сортировки завершающих столбцов в некластерном индексе может сделать большую разницу на планах, используемых конкретным запрос. Давайте возьмем следующий надуманный пример:

CREATE TABLE dbo.foo1(A INT, B INT, C INT); 
CREATE NONCLUSTERED INDEX foo1x ON dbo.foo1(B, C) INCLUDE(A); 

CREATE TABLE dbo.foo2(A INT, B INT, C INT); 
CREATE NONCLUSTERED INDEX foo2x ON dbo.foo2(B, C DESC) INCLUDE(A); 

INSERT dbo.foo1 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id] 
FROM sys.all_columns AS c CROSS JOIN sys.all_objects 
ORDER BY c.[object_id]; 

INSERT dbo.foo2 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id] 
FROM sys.all_columns AS c CROSS JOIN sys.all_objects 
ORDER BY c.[object_id]; 

Теперь давайте запустим эти два предложенные запросы и проверить планы:

SELECT A 
FROM (
     SELECT A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN 
     FROM dbo.foo1 
     ) q 
WHERE rn = 1; 

SELECT A 
FROM (
     SELECT A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN 
     FROM dbo.foo2 
     ) q 
WHERE rn = 1; 

Вот план запроса к dbo.foo1 (где C является ASC):

enter image description here

enter image description here

И вроде я уже говорил:

enter image description here


А вот план для запроса к DBO.foo2 (где С DESC):

enter image description here

enter image description here


Теперь, если вы добавите ИНЕКЕ внутреннего запроса (например WHERE B = -1024577103), планы более аналогичный. Но тогда это также подразумевает, что PARTITION BY не является необходимым и что для ограничения внешнего запроса это значение B также должно быть сопряжено. Однако моя точка зрения по-прежнему заключается в том, что хотя для конкретного запроса в вопросе направление сортировки каждого столбца в индексе может мало повлиять на план, но это неверно для всех запросов, которые могут использовать один и тот же индекс.

+0

Для этого самого вопроса 'C ASC' будет вести себя точно так же. – Quassnoi

+0

О подзапросе, он используется в списке выбора внешнего запроса. Таким образом, он должен вернуть один результат (или NULL) ... – Koen

+0

@Quassnoi, хотя это верно для самого плана, определение индекса лучше описывает его намерение (запрос, который он построил для удовлетворения). Вы уверены, что это поведение верно для очень большого количества одинаковых значений для B? –

0

Заказ имеет значение. Столбец, который находится в первом порядке, является самым важным.

Выбор индекса целиком основан на первом столбце. Индекс считается для использования только в том случае, если в запросе используется первый столбец, указанный в индексе. Поэтому, если в первом столбце нет совпадения, а столбец используется в предложениях JOIN, ORDER BY или WHERE, индекс полностью игнорируется.

0

Вы можете переписать это так:

SELECT m.a 
FROM (
     SELECT m.a, ROW_NUMBER() OVER (PARTITION BY m.b ORDER BY m.c DESC) RN 
     FROM outer_table o 
     JOIN my_table m 
     ON  m.b = o.b 
     ) q 
WHERE rn = 1 

но подзапрос может быть на самом деле быстрее (или не может).

Посмотреть эту запись в своем блоге:

+0

Для * этого * запроса вы должны сравнить план с индексом с C ASC и индексом с C DESC. Для индекса, где C является ASC, требуется дополнительная (и довольно дорогая) операция сортировки, и в зависимости от других факторов это может разлиться в tempdb (убедитесь, что имеется достаточное количество строк). Вот почему мне нравится мой индекс, где C - DESC - для некоторых запросов это имеет большое значение. (В качестве дополнительного бонуса обязательно попробуйте его в системе, в которой будет задействован параллелизм. :-)) –

+0

@Aaron: индекс можно перемещать в обоих направлениях, а 'C' заканчивается. 'DESC' или' ASC' здесь не будут иметь никакого значения. – Quassnoi

+0

Вы пробовали? –

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