Почему некластерный индекс улучшает производительность - PullRequest
0 голосов
/ 20 июня 2020

У меня есть одна таблица с именем Item , в ней около 80 миллионов строк:

DDL :

CREATE TABLE [dbo].[Item](
    [ItemID] [int] NOT NULL,
    [GroupID] [char](36) NULL,
    [KeyName] [varchar](50) NOT NULL,
    [KeyValue] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Item_User] PRIMARY KEY CLUSTERED 
(
    [ItemID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NonClusteredIndex-20170605-101521] ON [dbo].[Item]
(
    [GroupID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [Key_1] ON [dbo].[Item]
(
    [KeyName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Другая таблица с именем Order , в нем около десяти миллионов строк.

DDL :

CREATE TABLE [dbo].[Order](
    [OrderID] [int] IDENTITY(1,1) NOT NULL,
    [GroupID] [char](36) NOT NULL,
    [OrderNr] [varchar](512) NOT NULL,
    [ItemID] [int] NOT NULL,
    [Memo] [varchar](512) NOT NULL,
    [ServiceType] [char] NOT NULL,
 CONSTRAINT [PK_Order] PRIMARY KEY CLUSTERED 
(
    [OrderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NonClusteredIndex-Order_OrderNum] ON [dbo].[Order]
(
    [OrderNr] ASC,
    [ItemID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NonClusteredIndex-20191231-143827] ON [dbo].[Order]
(
    [GroupID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NonClusteredIndex-20191231-143949] ON [dbo].[Order]
(
    [ItemID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

При выполнении ниже SQL в моей реальной среде:

select 
        (select top 1 KeyValue from Item i where i.ItemID=o.ItemID) KeyValue, -- i.ItemID is primary key with Cluster index default
        o.Memo
from [dbo].[Order] o 
where ServiceType in ('X', '*') and OrderNr not like '9%' and OrderNr not like '54%';

Это занимает более 2 минут.

Ниже приводится фактический план выполнения ( Индексное сканирование ):

Execution plan

При выполнении ниже SQL:

select 
        (select top 1 KeyValue from Item i where i.ItemID=o.ItemID and i.GroupID=o.GroupID) KeyValue, --i.ItemID is cluster index and i.GroupID is non cluster index
        o.Memo
from [dbo].[Order] o 
where ServiceType in ('X', '*') and OrderNr not like '9%' and OrderNr not like '54%';

Это занимает менее 10 секунд в моей реальной среде.

Ниже приведен фактический план выполнения ( Поиск индекса ):

enter image description here

Из двух вышеуказанных планов вы увидите:

  1. Первый SQL использует только индекс кластера (Item. ItemID), но SQL выполняется Index Scan вместо Index Seek , его Rows Read составляет 80M.

  2. Второй SQL использует кластерный индекс (Item.ItemID) и некластерный индекс (Item.GroupID), но SQL выполняется Index Seek , его Rows Read всего 8M.

Версия сервера SQL в моей реальной среде 11.0.7462.6 .

И я создал одну MS SQL скрипку и сгенерировал 10К тестовых записей, пытаясь воспроизвести проблему. Но, к сожалению, обе команды SQL в скрипте, похоже, выполняются с одним и тем же планом, поведение в моей реальной среде отличается.

Кто-нибудь знает, почему оптимизатор использует сканирование индекса при первом выполнении SQL? Почему добавление одного некластерного индекса (Item.GroupID) может запустить его в Поиск индекса и значительно повысить производительность?

Спасибо.

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