Оценка мощности SARG, почему не полносканирование?
Почему нет полного сканирования (на SQL 2008 R2 и 2012)?
Данные теста:
DROP TABLE dbo.TestTable
GO
CREATE TABLE dbo.TestTable
(
TestTableID INT IDENTITY PRIMARY KEY,
VeryRandomText VarChar(50),
VeryRandomText2 VarChar(50)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
Insert Into dbo.TestTable(VeryRandomText, VeryRandomText2)
Values(Cast(Rand()*10000000 as VarChar(50)), Cast(Rand()*10000000 as VarChar(50)));
Set @i = @i + 1;
End
Go
CREATE Index IX_VeryRandomText On dbo.TestTable
(
VeryRandomText
)
Go
При выполнении запроса:
Select * From dbo.TestTable Where VeryRandomText = N'111' -- bad
Получить предупреждение (как и ожидалось, поскольку сравнение данных nchar с столбцом varchar):
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(nvarchar(50),[DemoDatabase].[dbo].[TestTable].[VeryRandomText],0)" />
Но затем я вижу план выполнения, и я вижу, что он не использует полносканирование, как я ожидал бы, но вместо этого ищет индекс.
2 ответа
При сравнении значений разных типов данных SQL Server следуйте Приоритет типа данных правила. Поскольку nvarchar имеет более высокий приоритет, чем varchar, SQL Server должен преобразовать данные столбца в nvarchar перед сравнением значений. Это означает применение функции в столбце, и это сделает запрос неприемлемым.
SQL Server делает все возможное, чтобы защитить вас от ваших ошибок, поэтому он использует технику, описанную Пол Уайт в блоге Сравнение сопоставлений SQL с сопоставлениями Windows
В принципе, сортировка Windows использует тот же алгоритм для varchar и nvarchar, где сортировка SQL использует другой алгоритм для данных varchar и тот же алгоритм, что и сортировка Windows для данных nvarchar.
Таким образом, переход от varchar к nvarchar при сортировке Windows будет использовать тот же алгоритм, и SQL Server может создавать ряд значений, в вашем случае, литерал nvarchar для получения строк из индекса столбца сортировки SQL varchar. Однако, когда сортировка столбца varchar представляет собой SQL-сортировку, которая невозможна из-за использования используемого алгоритма.
Update:
Демонстрация различных порядков сортировки для столбцов varchar с использованием окон и сопоставления sql.
Настройка схемы MS SQL Server 2014 :
create table T(C varchar(10));
insert into T values('a-b'),('aa'),('ac');
Запрос 1 :
select C
from T
order by C collate SQL_Latin1_General_CP1_CI_AS;
| C |
|-----|
| a-b |
| aa |
| ac |
Запрос 2 :
select C
from T
order by C collate Latin1_General_100_CI_AS;
| C |
|-----|
| aa |
| a-b |
| ac |
Вы должны помнить, что листовые узлы некластеризованного индекса состоят из страниц индексов, содержащих Кластерный ключ или RID, чтобы найти строку данных.
В вашем предложении where вы указываете VeryRandomText = N'111'
Так как на VeryRandomText существует Non-кластерный индекс (create index создаст некластеризованный индекс, если вы не явным образом расскажу, чтобы создать кластерный), самый дешевый способ найти данные - это сканировать индекс, чтобы найти rowid, а затем извлечь данные для строки.
Если вы создадите кластерный индекс
CREATE clustered Index IX_VeryRandomText On dbo.TestTable (VeryRandomText)
или первичный ключ на VeryRandomText, вы получите сканирование этого индекса.
Смотрите книги онлайн или здесь: http://www.sqlforge.com/w/Clustered_index, _nonclustered_index, _or_heap