Подходящие индексы для сортировки в функциях ранжирования - PullRequest
4 голосов
/ 12 октября 2010

У меня есть таблица, в которой хранятся отношения родитель-ребенок между элементами. Они могут быть изменены с течением времени, и необходимо вести полную историю, чтобы я мог спросить, как были отношения в любое время.

Таблица выглядит примерно так (я удалил несколько столбцов, первичный ключ и т. Д., Чтобы уменьшить шум):

CREATE TABLE [tblRelation](
    [dtCreated] [datetime] NOT NULL,
    [uidNode] [uniqueidentifier] NOT NULL,
    [uidParentNode] [uniqueidentifier] NOT NULL
)

Мой запрос на получение отношений в определенное время выглядит следующим образом (предположим, @dt - это дата и время с желаемой датой):

SELECT *
  FROM (
    SELECT ROW_NUMBER() OVER (PARTITION BY r.uidNode ORDER BY r.dtCreated DESC) ix, r.*
      FROM [tblRelation] r
      WHERE (r.dtCreated < @dt)
    ) r
  WHERE r.ix = 1

Этот запрос работает хорошо. Однако производительность пока не так хороша, как хотелось бы. Если посмотреть на план выполнения, он сводится к сканированию кластерного индекса (36% стоимости) и сортировке (63% стоимости).

Какие индексы я должен использовать, чтобы сделать этот запрос быстрее? Или вообще есть лучший способ выполнить этот запрос к этой таблице?

Ответы [ 2 ]

3 голосов
/ 12 октября 2010

Идеальный индекс для этого запроса - ключевые столбцы uidNode, dtCreated и включенные столбцы всех оставшихся столбцов в таблице, чтобы индекс покрывал при возврате r.*.Если запрос, как правило, будет возвращать только относительно небольшое количество строк (что, вероятно, связано с фильтром WHERE r.ix = 1), возможно, не стоит делать покрытие индекса, хотя стоимость поиска по ключевым словам может не перевесить негативные последствиябольшой индекс на CUD заявления.

1 голос
/ 30 октября 2010

Функции окна / ранга в SQL Server 2005 не всегда оптимальны (основываясь на ответах здесь).Видимо лучше в SQL Server 2008

Еще одна альтернатива - что-то вроде этого.Я бы имел некластеризованный индекс на (uidNode, dtCreated), включая все другие столбцы, необходимые для SELECT.С учетом того, что сказал Мартин Смит о поисках.

WITH MaxPerUid AS
(
    SELECT
       MAX(r.dtCreated) AS MAXdtCreated, r.uidNode
    FROM
       MaxPerUid
    WHERE
       r.dtCreated < @dt
    GROUP BY
       r.uidNode
)
SELECT
    ...
FROM
   MaxPerUid M
   JOIN
   MaxPerUid R ON M.uidNode = R.uidNode AND M.MAXdtCreated = R.dtCreated
...