SQL Server 2008处理隐式数据类型转换在执行计划中的增强

什么是隐式">数据类型转换:

当我们在语句的where 条件等式的左右提供了不同数据类型的列或者变量,SQL Server在处理等式之前,将其中一端的数据转换成跟另一端数值的数据类型一致,这个过程叫做隐式数据类型转换。

比如 char(50)=varchar(50), char(50)=nchar(50), int=float, int=char(20) 这些where 条件的等式都会触发隐式数据类型转换。

但是,对于某些数据类型转换过程中,可以转换的方向只是单向的。例如:

如果你试图比较INT和FLOAT的列,INT数据类型必须被转换成FLOAT型"CONVERT(FLOAT,C_INT) = C_FLOAT".

如果你试图比较char和nchar的列,char数据类型必须被转换成unicode型"CONVERT(nchar,C_char) = C_nchar"

因此,我们在.net 或者java的程序中,经常容易遇到以下类型的性能问题:

CREATE TABLE [TEST_TABLE] (

[TAB_KEY] [varchar] (5) NOT NULL ,

[Data] [varchar] (10) NOT NULL ,

CONSTRAINT [TEST_TABLE_PK] PRIMARY KEY CLUSTERED

(

[TAB_KEY]

) ON [PRIMARY]

) ON [PRIMARY]

GO

declare @p1 int

set @p1=0

exec sp_prepexec @p1 output,N'@P0 nvarchar(4000)',N'select TAB_KEY,Data from TEST_TABLE where TAB_KEY = @P0',N'0'

select @p1

在这个例子中,表的定义TAB_KEY是varchar型的字段,而程序传递的参数类型为Unicode类型的nvarchar(4000). 当语句执行到where TAB_KEY = @P0,SQL Server会按照如下方式执行:

select TAB_KEY,Data from TEST_TABLE where convert(nvarchar(5),TAB_KEY)=@p0

语句一旦变成这样,TAB_KEY上创建的clustered index就无法快速的查找索引并返回对应的行了。

在这里顺便提一下为什么java程序默认传递unicode类型的参数. 如果使用的是Microsoft JDBC provider,那么这里有个参数sendStringParametersAsUnicode,默认是true. 这个参数是用来控制传递的参数是不是unicode类型的。如果我们的SQL Server表的数据类型都不是unicode,需要在connection string中声明这个参数是false。http://msdn.microsoft.com/en-us/library/ms378988.aspx

我们使用以下脚本往测试表中插入几千行数据,然���检查执行计划:

declare @i int

set @i=0

while(1=1)

begin

insert into TEST_TABLE values(@i,'a')

set @i=@i+1

end

SQl2008、2005、2000 execution plan

Rows         Executes    StmtText

------------ ----------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------

1            1           select TAB_KEY,Data from TEST_TABLE where TAB_KEY = @P0

1            1             |--Clustered Index Scan(OBJECT:([aaa].[dbo].[TEST_TABLE].[TEST_TABLE_PK]), WHERE:(CONVERT_IMPLICIT(nvarchar(5),[aaa].[dbo].[TEST_TABLE].[TAB_KEY],0)=[@P0]))

在SQL 2000和2005,该语句得到的执行计划是同样的, SQL Server对测试表TEST_TABLE做了clustered index 扫描,即全表扫描,然后返回一行数据。在这里我们很清楚的看到有个CONVERT_IMPLICIT发生,并且将TAB_KEY转换成了nvarchar(5),由于索引上的列发生了数据类型转换,导致索引保存的数据无法直接用来做比较,因此SQL Server需要将所有行的TAB_KEY扫描转换后跟@p0做比较得到需要返回的数据。

当我们在SQL 2008 中做同样的测试是,我们发现执行计划变了!

Rows        Executes     StmtText

----------- ------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1           1            select TAB_KEY,Data from TEST_TABLE where TAB_KEY = @P0                                                                                                                                                                                                                     1           0

1           1              |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1005], [Expr1006], [Expr1004]))

1           1                   |--Compute Scalar(DEFINE:(([Expr1005],[Expr1006],[Expr1004])=GetRangeThroughConvert([@P0],[@P0],(62))))

1           1                   |    |--Constant Scan

1           1                   |--Clustered Index Seek(OBJECT:([aa].[dbo].[TEST_TABLE].[TEST_TABLE_PK]), SEEK:([aa].[dbo].[TEST_TABLE].[TAB_KEY] > [Expr1005] AND [aa].[dbo].[TEST_TABLE].[TAB_KEY] < [Expr1006]), WHERE:(CONVERT_IMPLICIT(nvarchar(5),[aa].[dbo].[TEST_TABLE].[TAB_KEY],0)=[@P0]) ORDERED FORWARD)

这个执行计划看起来变得复杂了很多,我们注意到,这里出现了一个操作叫做GetRangeThroughConvert(),在这里,SQL Server由于不能直接对varchar(5)的列用nvarchar(4000)的值进行seek,因此,SQL Server必须将nvarchar转换成varchar。但是由于这个转换可能导致数据丢失,SQL Server采用了另一种做法,首先扩展了一个varchar类型的范围,确保可以转换成我们目标的nvarchar值的varchar数据落在这个范围之内,然后使用这个范围去对index直接做seek。得到了返回的满足范围的少量数据以后,对这个范围内的少量数据进行数据类型转换,然后用来和nvarchar的值比较,最终准确的返回结果集。在这样一个过程中,SQL Server采用了一种迂回的方式使用了index seek而避免了表扫描。

Compute Scalar(DEFINE:(([Expr1005],[Expr1006],[Expr1004])=GetRangeThroughConvert([@P0],[@P0],(62)))) --在这里计算出来范围的两个边界值,然后将语句重写为以下模式:

select TAB_KEY, Data from TEST_TABLE where TAB_KEY>[Expr1005] and TAB_KEY < [Expr1006] and convert(nvarchar(5),TAB_KEY)=@p0

其中“TAB_KEY>[Expr1005] and TAB_KEY < [Expr1006]” 就用来做index seek。

因此,在SQL 2008中我们就不会再次面对由于客户程序定于参数的类型和数据表的数据类型不一致而带来的无法使用index的问题。

时间: 2025-01-20 18:03:04

SQL Server 2008处理隐式数据类型转换在执行计划中的增强的相关文章

防止ADO连接SQL Server时的隐式连接

ado|server 防止ADO连接SQL Server时的隐式连接Report Date:   2002/9 Prepared by:     郑            昀 Article last modified on 2002-9 The information in this article applies to: ü         Microsoft SQL Server 2000,7.0 ü         Microsoft ADO 2.5问题陈述:数据库服务器:Microso

Sql Server函数全解&lt;三&gt;数据类型转换函数和文本图像函数

原文:Sql Server函数全解<三>数据类型转换函数和文本图像函数 一:数据类型转换函数 在同时处理不同数据类型的值时,SQL Server一般会自动进行隐士类型转换.对于数据类型相近的值是有效的,比如int和float,但是对于其它数据类型,例如整型和字符类型,隐士转换就无法实现了,此时必须使用显示转换.为了实现这种显示转换,T-SQL提供了两个显示转换函数,分别是CAST和CONVERT函数. CAST(x AS type)和CONVERT(type,x)函数将一个类型的值转换为另一个

【多图】SQL Server 2000如何向SQL Server 2008 R2推送数据

最近做的一个项目要获取存在于其他服务器的一些数据,为了安全起见,采用由其他"服务器"向我们服务器推送的方式实现.我们服务器使用的是sql server 2008 R2,其他"服务器"使用的都是SQL Server 2000,还都是运行在Windows XP上的,整个过程遇到了一些问题,也参考了一些文档,最终费了好多事才算搞定. [一.配置分发服务器] SQLServer 2000的复制服务包括三个角色:发布服务器.分发服务器和订阅服务器,关系如图1所示.   图1

SQL Server 2000向SQL Server 2008 R2推送数据图文教程_mssql2008

最近做的一个项目要获取存在于其他服务器的一些数据,为了安全起见,采用由其他"服务器"向我们服务器推送的方式实现.我们服务器使用的是sql server 2008 R2,其他"服务器"使用的都是SQL Server 2000,还都是运行在Windows XP上的,整个过程遇到了一些问题,也参考了一些文档,最终费了好多事才算搞定. [一.配置分发服务器] SQLServer 2000的复制服务包括三个角色:发布服务器.分发服务器和订阅服务器,关系如图1所示. 图1 其中

sql server 2008 R2删除重复数据的方法

推荐方法3 --方法1: SELECT  * FROM    ( SELECT    Row_Number() OVER ( PARTITION BY [orderno] ORDER BY ( SELECT                                                              0                                                              ) ) AS RowNO ,        

odbc-关于SQL server 2008 通过ODBC数据导入时出现“索引超出数组界限”

问题描述 关于SQL server 2008 通过ODBC数据导入时出现"索引超出数组界限" 各位大虾好! 我在通过ODBC向SQL2008导入数据时,弹出"索引超出数组界限"这个警示窗口,请问问题在哪里?怎么解决? 环境:系统win2008 64位 数据库:SQL2008 R2 64位 补丁为SP3补丁 不知道我说的清楚不? 解决方案 源数据是什么格式的,换一个小一点的数据集导入有问题么?有没有更多提示信息. 解决方案二: 我用server2000导入就没有问题

SQL Server 2008数据表迁移至Postgres Plus详细步骤

一.概述 目前在市场上有许多数据库厂商,并且被许多数据密集型应用所采用,因此,许多时候人们需要移植应用程序以使用不同数据库中的数据,或者从不同数据库中迁移数据以供自己的应用程序之用.一般情况下,业内多采用数据迁移方式,因为这样做相对容易一些. Migration Studio是一款从诸如SQL Server.Oracle.MySQL等各种数据库向http://www.aliyun.com/zixun/aggregation/14171.html">Postgres自动迁移数据和业务逻辑的工

SQL Server 2008中的数据表压缩功能详细介绍_mssql2008

SQL Server 2005 SP2为我们带来了vardecimal功能,当时针对decimail和numeric数据类型推出了新的存储格式--vardecimal.vardecimal存储格式允许 decimal和numeric数据类型的存储作为一个可变长度列. 这项功能使得原来定长的decimal数据在数据文件中以可变长的格式存储,据称这项功能可以为典型的数据仓库节省30%的空间,而SQL Server 2008在这一基础上又进一步增强了数据压缩功能.SQL Server 2008现在支持

初探 SQL Server 2008 “Katmai”

微软下一代商业智能平台SQL Server 2008数据库,代号为:"Katmai ",而且公布了一些远景和目標. SQL Server 2008希望以更安全.更具延展性.更高的管理能力,而成為一个全方位企业资料.数据管理平台.其功能说明如下: 1.保护数据库咨询 SQL Server 2008本身将提供对整个数据库.数据表与Log加密的机制,并且程式存取加密数据库时,完全不需要修改任何程序. 2. 花费更少的时间在服务器的管理操作 SQL Server 2008将会采用一种Polic