Как LIKE "% ..." может искать по индексу?
Я бы ожидал этих двоихSELECT
s иметь одинаковый план выполнения и производительность. Так как наLIKE
Я ожидаю сканирования индекса. Когда я запускаю это и смотрю на планы, первыйSELECT
ведет себя как положено (при сканировании). Но второеSELECT
План показывает индекс поиска и работает в 20 раз быстрее.
Код:
-- Uses index scan, as expected:
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401'
-- Uses index seek somehow, and runs much faster:
declare @empty VARCHAR(30) = ''
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401' + @empty
Вопрос:
Как SQL Server использует поиск по индексу, когда шаблон начинается с подстановочного знака?
Бонусный вопрос:
Почему конкатенация пустой строки меняет / улучшает план выполнения?
Подробности:
Существует некластеризованный индексAccounts.AccountNumber
Есть и другие индексы, но поиск и сканирование включеныэтот индекс.Accounts.AccountNumber
столбец обнуляемыйvarchar(30)
Сервер SQL Server 2012Определения таблиц и индексов:
CREATE TABLE [updatable].[AccountAction](
[ID] [int] IDENTITY(1,1) NOT NULL,
[AccountNumber] [varchar](30) NULL,
[Utility] [varchar](9) NOT NULL,
[SomeData1] [varchar](10) NOT NULL,
[SomeData2] [varchar](200) NULL,
[SomeData3] [money] NULL,
--...
[Created] [datetime] NULL,
CONSTRAINT [PK_Account] PRIMARY KEY NONCLUSTERED
(
[ID] 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 [IX_updatable_AccountAction_AccountNumber_UtilityCode_ActionTypeCd] ON [updatable].[AccountAction]
(
[AccountNumber] ASC,
[Utility] ASC
)
INCLUDE ([SomeData1], [SomeData2], [SomeData3]) 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 CLUSTERED INDEX [CIX_Account] ON [updatable].[AccountAction]
(
[Created] 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]
ПРИМЕЧАНИЕ: вотфактический план выполнения для двух запросов. Имена объектов немного отличаются от приведенного выше кода, потому что я пытался сделать вопрос простым.