Індекси SQL Server - зростаючі чи спадаючі, яка різниця це має?


138

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


Відповіді:


136

Це в першу чергу має значення при використанні складених індексів:

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з будь-якої таблиці, завжди є кінцевими стовпцями будь-якого іншого індексу цієї таблиці.


1
Коли ви говорите "не для ...", ви маєте на увазі, що це не буде працювати або виступ буде жахливим?
Ніл N

5
Я маю на увазі, що індекс не буде використаний для запиту. Звичайно, сам запит спрацює, але продуктивність буде поганою.
Quassnoi

1
У першому розділі чи не повинен другий приклад говорити "ЗАМОВИТИ 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 %% )

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


Дякую Мартін за цей чудовий підказку, це дійсно допомогло мені в
питаннях про

Цікаво, чи є у мене низхідний індекс, а потім виберіть мій стовпець із mytable, де indexed_column = \ @myvalue швидше, коли \ @myvalue ближче до максимально можливого значення, ніж у випадку, коли \ @myvalue закритий до мінімально можливого значення.
Лайош Арпад

@LajosArpad чому б швидше? Б дерева - збалансовані дерева. Глибина дерева однакова.
Мартін Сміт

@MartinSmith глибина однакова, але я сумніваюся, що порядок братів і сестер не змінив би значення
Lajos Arpad

@MartinSmith, якщо порядок братів і сестер має навіть незначну різницю в продуктивності, то запуск мільйонів вибірок додасться, не кажучи вже про багатовимірні приєднання.
Лайош Арпад

8

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

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

@Quassnoi - прекрасний приклад того, коли це має значення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.