Индексы SQL Server - по возрастанию или по убыванию, какая разница?

142

Когда вы создаете индекс для столбца или количества столбцов в MS SQL Server (я использую версию 2005), вы можете указать, что индекс для каждого столбца будет либо по возрастанию, либо по убыванию. Мне трудно понять, почему этот выбор вообще существует. Разве поиск не будет таким же быстрым при использовании методов двоичной сортировки? Какая разница, какой порядок я выберу?

Джошуа Кармоди
источник

Ответы:

139

В первую очередь это имеет значение при использовании составных индексов:

CREATE INDEX ix_index ON mytable (col1, col2 DESC);

может использоваться для:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

или:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

, но не для:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

Индекс по одному столбцу можно эффективно использовать для сортировки обоими способами.

Подробнее читайте в статье в моем блоге:

Обновить:

Фактически, это может иметь значение даже для индекса с одним столбцом, хотя это не так очевидно.

Представьте себе индекс столбца кластеризованной таблицы:

CREATE TABLE mytable (
       pk INT NOT NULL PRIMARY KEY,
       col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)

Индекс on col1сохраняет упорядоченные значения col1вместе со ссылками на строки.

Поскольку таблица кластеризована, ссылки на строки фактически являются значениями pk. Они также упорядочены в пределах каждого значения col1.

Это означает, что листья индекса фактически упорядочены (col1, pk), и этот запрос:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

не нуждается в сортировке.

Если мы создадим индекс следующим образом:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

, то значения col1будут отсортированы по убыванию, но значения pkвнутри каждого значения col1будут отсортированы по возрастанию.

Это означает, что следующий запрос:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk DESC

может быть подан , ix_mytable_col1_descно не ix_mytable_col1.

Другими словами, столбцы, составляющие a CLUSTERED INDEXв любой таблице, всегда являются конечными столбцами любого другого индекса в этой таблице.

Quassnoi
источник
1
Когда вы говорите «не для ...», вы имеете в виду, что это не сработает или исполнение будет ужасным?
Neil N
5
Я имею ввиду, что индекс не будет использоваться для запроса. Сам запрос, конечно, будет работать, но производительность будет плохой.
Quassnoi
1
Разве во втором примере в первом разделе не должно быть написано «ORDER BY col1 DESC, col2 DESC»?
Митч Уит
71

Для истинного индекса с одним столбцом это не имеет большого значения с точки зрения оптимизатора запросов.

Для определения таблицы

CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] ASC))

Запрос

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

Использует упорядоченное сканирование с направлением сканирования, BACKWARDуказанным в плане выполнения. Однако есть небольшая разница в том, что в настоящее время FORWARDможно распараллеливать только сканирование.

План

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

Посмотреть результаты фрагментации

                    avg_fragmentation                    avg_fragment
name   page_count   _in_percent         fragment_count   _size_in_pages
------ ------------ ------------------- ---------------- ---------------
T1     1000         0.4                 5                200
T2     1000         99.9                1000             1

для сценария ниже

/*Uses T1 definition from above*/
SET NOCOUNT ON;

CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] DESC))

BEGIN TRAN

GO
INSERT INTO T1 DEFAULT VALUES
GO 1000
INSERT INTO T2 DEFAULT VALUES
GO 1000

COMMIT

SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 
UNION ALL 
SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 

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

SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T1
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
UNION ALL
SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T2
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )

введите описание изображения здесь

Мартин Смит
источник
Спасибо, Мартин, за этот замечательный СОВЕТ, это действительно помогло мне в запросах ранга
TheGameiswar
Интересно, есть ли у меня убывающий индекс, а затем выберите mycolumn из mytable, где indexed_column = \ @myvalue быстрее, когда \ @myvalue ближе к максимально возможному значению, чем в случае, когда \ @myvalue закрывается до минимально возможного значения.
Лайош Арпад,
@LajosArpad, почему нужно быть быстрее? B-деревья - это сбалансированные деревья. Глубина дерева одинакова для обоих.
Мартин Смит
@MartinSmith, глубина такая же, но я сомневаюсь, что порядок братьев и сестер не имеет значения,
Лайош Арпад,
@MartinSmith, если порядок братьев и сестер имеет хотя бы небольшую разницу в производительности, то выполнение миллионов выборок будет складываться, не говоря уже о многомерных соединениях.
Лайош Арпад,
8

Порядок сортировки имеет значение, когда вы хотите получить много отсортированных данных, а не отдельные записи.

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

@Quassnoi - отличный пример того, когда это действительно важно.

Майкл Харен
источник