小议隐式转换引起的问题
隐式转换(Implicit conversion) ,这个情况每个程序员都或多或少的遇到过,这里我结合实际情况简单描述下常见的问题以及如何解决并阐述下原理。
所谓隐式转换主要出现在我们T-SQL语句中的where 条件里面,我们先从原因上去看一下为什么会出现隐式转换。
出现隐式转换的情况和结果:
当SQL server遇到一个不匹配类型的表达式的时候,它有两种可能:1.使用隐式转换并能够执行;2.转换错误而导致执行失败。
在进行之前,我们先提出一个概念:
数据类型优先级
当两个不同数据类型的表达式用运算符组合后,数据类型优先级规则指定将优先级较低的数据类型转换为优先级较高的数据类型。
如果此转换不是所支持的隐式转换,则返回错误。 当两个操作数表达式具有相同的数据类型时,运算的结果便为该数据类型。
SQL Server 对数据类型使用以下优先级顺序:
- 用户定义数据类型(最高)
- sql_varian t
- xml
- datetimeoffset
- datetime2
- datetime
- smalldatetime
- date
- time
- float
- real
- decimal
- money
- smallmoney
- bigint
- int
- smallint
- tinyint
- bit
- ntext
- text
- image
- timestamp
- uniqueidentifier
- nvarchar(包括 nvarchar(max))
- nchar
- varchar(包括 varchar(max))
- char
- varbinary(包括 varbinary(max))
- binary(最低)
1.隐式转换成功的情况下有两种情况,我们结合执行计划来看一下
主键为int 类型和主键为varchar类型的情况下隐式转换有什么不同
图1.SalesOrderId主键为Int类型 图2.SalesOrderId主键为varchar类型
通过执行sql语句和执行计划我们很容易发现,当主键为Int类型的时候,我们的参数为varchar类型,结果采用了聚集索引查找,效率较高(图1);
而图2,主键改为varchar类型,参数改为int类型执行计划采用了非聚集索引扫描,IO势必增加不少。
结合我们之前提出的优先级概念,得知如果参数的数据类型较低则隐式转换后采用了正确的优化,即无损转换,而当参数优先级较低的时候则对性能产生了损耗。
下面我们看一下详细的执行计划来作证上面的观点:
有这个对比可以发现一个是对参数进行了转换,一个是对数据表的字段进行了转换,可以想象由此得出的问题。
当然我们也可以通过转换参数的类型的方式来解决这个问题,但是由与精度不同有时候会产生问题,比如转换一个REAL型到INT整型
CONVERT(INT,@Real);需要注意的是联接丛书页面中涵盖了一个兼容性矩阵,描述了SQL server如何处理数据类型转换的所有可能性,意思就
是说并非所有的隐式转换都可行,有些转换是不被允许的。简单说基本上, 有三种比较表达式选项:
1.转换右侧数据类型为左侧数据类型。
2.转换左侧数据类型为右左侧数据类型。
3.将两者转换到第三方数据类型
这部分就不一一赘述了。
总结: 本文主要介绍了隐式转换产生的原因及原理,实例证明了对于查询效率产生了明显的影响。具体解决上要根据实际情况进行数据类型的转换或者注意类型的兼容性和优先级。由于隐式转换查询带来的性能问题甚至由于主键扫描带来的锁的问题,都需要开发人员了解这部分的原理,从根源上避免这类事件的发生。