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

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

Ответы [ 3 ]

124 голосов
/ 13 апреля 2009

Это особенно важно при использовании с составными индексами:

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)

Индекс 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 в любой таблице, всегда являются конечными столбцами любого другого индекса в этой таблице.

66 голосов
/ 21 февраля 2012

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

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

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

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

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

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

enter image description here

8 голосов
/ 13 апреля 2009

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

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

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

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