2009-04-13 3 views
102

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

ответ

105

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

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

+0

Когда вы говорите «не ...» Вы имеете в виду, что не будет работать, или производительность будет ужасно? –

+2

Я имею в виду, что индекс не будет использоваться для запроса. Разумеется, сам запрос будет работать, но производительность будет плохой. – Quassnoi

+0

В первом разделе не следует указывать второй пример: «ORDER BY col1 DESC, col2 DESC»? –

8

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

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

@Quassnoi предоставляет great example от делает вопрос.

53

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

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

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 

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

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

+0

Спасибо, Мартин за этот отличный совет, это действительно помогло мне в ранговых запросах – TheGameiswar

+0

Интересно, есть ли у меня нисходящий индекс, а затем выберите mycolumn from mytable, где indexed_column = \ @myvalue быстрее, когда \ @myvalue ближе к максимально возможному значению чем в случае, когда \ @myvalue закрывается до минимально возможного значения. –

+0

@ LajosArpad почему бы быстрее? Деревья B - это сбалансированные деревья.Глубина дерева одинакова для обоих. –

Смежные вопросы