Когда вы создаете индекс в столбце или количестве столбцов в MS SQL Server (я использую версию 2005), вы можете указать, что индекс для каждого столбца будет либо возрастающим, либо убывающим. Мне трудно понять, почему этот выбор даже здесь. Используя двоичные методы сортировки, не будет ли поиск таким же быстрым в любом случае? Какая разница, какой порядок я выбираю?
Индексы SQL Server - по возрастанию или по убыванию, какая разница?
Ответ 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
.
Однако он может иметь большое значение с точки зрения логической фрагментации. Если индекс создается с нисходящими ключами, но новые строки добавляются с возрастающими значениями ключа, вы можете завершить каждую страницу из логического порядка. Это может серьезно повлиять на размер чтения 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 %% )
Ответ 3
Порядок сортировки имеет значение, когда вы хотите получить множество отсортированных данных, а не отдельные записи.
Обратите внимание, что (как вы предлагаете с вашим вопросом) порядок сортировки обычно намного менее значителен, чем индексы, которые индексируются (система может читать индекс в обратном порядке, если порядок противоположный тому, что он хочет). Я редко даю индексный порядок сортировки любой мысли, тогда как я мучаюсь над столбцами, охватываемыми индексом.
@Quassnoi предоставляет отличный пример, когда это имеет значение.