热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

什么是隐式数据类型转换:当我们在语句的where条件等式的左右提供了不同数据类型的列或者变量,SQLServer在处理等式之前,将其中一端的数据转换成跟另一端数值的数据类型一致,这个过程叫做隐式数据类型转换。比如char(50)varchar(50),char(50)nchar

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

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

当我们在语句的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的问题。

推荐阅读
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 《树莓派开发实战(第2版)》——2.2 创建模型和运行推理:重回Hello World
    本节书摘来异步社区《概率编程实战》一书中的第2章,第2.2节,作者:【美】AviPfeffer(艾维费弗)&# ... [详细]
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
  • 翻译 | 编写SVG的口袋指南(上)
    作者:DDU(沪江前端开发工程师)本文是原文翻译,转载请注明作者及出处。简介ScalableVectorGraphics(SVG)是在XML中描述二维图形的语言。这些图形由路径,图 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了Python版Protobuf的安装和使用方法,包括版本选择、编译配置、示例代码等内容。通过学习本教程,您将了解如何在Python中使用Protobuf进行数据序列化和反序列化操作,以及相关的注意事项和技巧。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
author-avatar
手机用户2502933647
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有