Jān*_*nis 11 performance sql-server sql-server-2008-r2 sql-server-2012 query-performance
为什么没有全扫描(在 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
Run Code Online (Sandbox Code Playgroud)
执行查询时:
Select * From dbo.TestTable Where VeryRandomText = N'111' -- bad
Run Code Online (Sandbox Code Playgroud)
收到警告(正如预期的那样,因为将 nchar 数据与 varchar 列进行比较):
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(nvarchar(50),[DemoDatabase].[dbo].[TestTable].[VeryRandomText],0)" />
Run Code Online (Sandbox Code Playgroud)
但是后来我看到了执行计划,并且我可以看到,它没有像我期望的那样使用全扫描,而是使用索引查找。
当然,这很好,因为在这种特殊情况下,执行速度比完全扫描要快得多。
但我不明白 SQL Server 是如何决定制定这个计划的。
此外 - 如果服务器排序规则是服务器级别和 SQL Server 排序规则数据库级别的 Windows 排序规则,那么它会导致对同一查询进行全面扫描。
比较不同数据类型的值时,SQL Server 遵循数据类型优先规则。由于 nvarchar 的优先级高于 varchar,因此 SQL Server 必须在比较值之前将列数据转换为 nvarchar。这意味着在列上应用一个函数,这将使查询不可 sargable。
然而,SQL Server 确实尽力保护您免受错误的影响,因此它使用 Paul White 在博客文章Dynamic Seeks and Hidden Implicit Conversions 中描述的技术来搜索一系列值,然后进行最终比较,使用将列值转换为 nvarchar,在残差谓词中过滤掉任何误报。
正如您所指出的,当列的排序规则是 SQL 排序规则时,这不起作用。我相信,原因可以在比较 SQL 排序规则与 Windows 排序规则一文中找到
基本上,Windows 归类对 varchar 和 nvarchar 使用相同的算法,其中 SQL 归类对 varchar 数据使用不同的算法,对 nvarchar 数据使用与 Windows 归类相同的算法。
因此,在 Windows 排序规则下从 varchar 到 nvarchar 将使用相同的算法,并且 SQL Server 可以从 nvarchar 文字中生成一系列值,以从 varchar SQL 排序规则列索引中获取行。但是,当 varchar 列的排序规则是 SQL 排序规则时,由于使用的算法不同,这是不可能的。
更新:
使用 windows 和 sql 排序规则对 varchar 列的不同排序顺序的演示。
MS SQL Server 2014 架构设置:
create table T(C varchar(10));
insert into T values('a-b'),('aa'),('ac');
Run Code Online (Sandbox Code Playgroud)
查询 1:
select C
from T
order by C collate SQL_Latin1_General_CP1_CI_AS;
Run Code Online (Sandbox Code Playgroud)
结果:
| C |
|-----|
| a-b |
| aa |
| ac |
Run Code Online (Sandbox Code Playgroud)
查询 2:
select C
from T
order by C collate Latin1_General_100_CI_AS;
Run Code Online (Sandbox Code Playgroud)
结果:
| C |
|-----|
| aa |
| a-b |
| ac |
Run Code Online (Sandbox Code Playgroud)