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

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

Ответ 1

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

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

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

Подробнее см. статью в моем блоге:

Update:

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

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

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

Индекс на 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.

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

Ответ 2

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

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

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.

Plan

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

См. результаты фрагментации

                    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

для script ниже

/*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 %% )

enter image description here

Ответ 3

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

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

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