译自:
<a href="http://www.mssqltips.com/sqlservertip/2749/sql-server-data-type-precedence/?utm_source=dailynewsletter&utm_medium=email&utm_content=headline&utm_campaign=2012814">http://www.mssqltips.com/sqlservertip/2749/sql-server-data-type-precedence/?utm_source=dailynewsletter&utm_medium=email&utm_content=headline&utm_campaign=2012814</a>
我在我的应用程序中使用简单的查询/存储过程访问一个很大的表。但执行了很长时间。在where子句中,我使用了有索引并且高选择性(selective)并且没有用函数包裹的字段。但是看起来就像没有使用索引一样,问题出在那里?
create proceduredbo.PrecedenceTest
(
@AccountNumber varchar(10)
)
as
begin
set nocount on
select *
from Sales.Customer
where AccountNumber = @AccountNumber
end
go
exec dbo.PrecedenceTest'AW00030113'
执行计划如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauMTYmR2N2MTMlRzM4ADO5ATY2QGNzMzN2YGMmBzN1QTYfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.jpg)
接着让我们在参数上做些小改动,把它改为nvarchar(10),然后重新执行语句:
执行计划显示,优化器选择了扫描TerritoryID上的索引。
检查Filter操作,可以看到AccountNumber列上被隐式转换了类型来匹配传入的参数。由于数据类型varchar比参数类型nvarchar级别更低,导致其所在的索引失效。
现在让我们验证一下,在较低级别的数据类型作为查找参数下的情况。在这个例子中,Person.Person 表的LastName列是nvarchar类型,并且上面存在一个可用的索引,存储过程传入的参数是varchar类型:
执行计划显示,优化器选择使用了索引查找:
点开Index Seek的详细信息,可以看到列LastName的数据类型因为传入参数的原因而隐式转换成更高级的nvarchar类型。
当索引列不再被转换所影响时,优化器可以自由地选择最优执行计划。
不管你是在应用程序或者在存储过程中定义查询参数,确保查询参数中的数据类型和查询列的数据类型相吻合能避免索引扫描和其他转换引起的问题。
user-defined data types (highest)
sql_variant
xml
datetimeoffset
datetime2
datetime
smalldatetime
date
time
float
real
decimal
money
smallmoney
bigint
int
smallint
tinyint
bit
ntext
text
image
timestamp
uniqueidentifier
nvarchar (including nvarchar(max) )
nchar
varchar (including varchar(max) )
char
varbinary (including varbinary(max) )
binary (lowest)