轉自:http://www.netfocus.cn/peoplearticle995.html

本文主要介绍写SQL的另外两个误区:
1、 存储过程中使用局部变量而不使用参数变量(就是存储过程输入参数)做where条件
2、 查询条件中类型不匹配

这两种错误都是非常非常容易犯且非常发指的错误,特别是2,太多次见过了。

一、关于存储过程使用局部变量,我们举例说明。

有这么一张表

存储过程:

create proc test

(

@id int

)

as

select * from charge where charge_no > @id

那么exec test 99998,执行计划为:

请注意上图中的估计行数。

但是如果把存储过程修改为:

alter proc test

(

@id int

)

as

declare @local int

set @local = @id

select * from charge where charge_no > @local

再次观察exec test 99998的查询计划:

请再次注意估计行数,现在是30000了。而我们都知道,修改前存储过程和修改后的输出结果集都没有任何变化,为2。

由于charge_no是聚集索引,而我们的查询条件是where charge_no > XXX,不论SQLServer估计行数有多大,伊都会使用相同的clustered index seek查找到XXX,然后直接顺序遍历基础表剩下的叶节点。

但是,若charge_no是非聚集索引,由于估计结果集行数大小由两行变成了总行数的百分之三十(使用局部变量做查询条件,这种where AAA > BBB,SQLServer无法估计结果集大小,所以它使用默认估计值:30%),nonclustered index seek变成nonclustered index scan(SQL2k5中若不是覆盖查询,会是clustered index scan),这是巨大的性能损耗,必须避免。

在这里顺带着再次强调另外一个问题:缓存的查询计划可能会强力的伤害性能。为了更详细的说明它,我们把存储过程test改为:

alter proc test

(

@id int

)

as

select * from charge where charge_no > @id

然后看看执行计划exec test 99998(见上面的图,不重复贴了)。再来看看exec test 1的执行计划:

我们可以注意到,尽管真实的结果集变动非常巨大,但是查询计划还是完全不变,SQLServer在使用缓存。这种情况在使用聚集索引时不会让查询变得更糟,但是使用非聚集索引就会差上十万八千里,IO开销会差上n个数量级(n取决于真实的结果集)。

所以如果你的查询由于输入参数的不同,选择性变动剧烈,最好在创建存储过程的时候使用 WITH RECOMPILE 选项。即:

create proc test

(

@id int

)

with recompile

as

select * from charge where charge_no > @id

OK,但并不是所有的情况下在查询条件中使用局部变量都有问题。如果查询条件中涉及的索引,SQLServer发现伊的分布密度非常小(比如一个identity(1,1)列或者一个unique),那么在where AAA = XXX的情况下,SQLServer仍然会认为结果集相对总行数很小,而选择index seek类的查询计划。

二、 查询条件中的类型不匹配。

所谓的类型不匹配是说,查询条件where AAA = @var,列AAA的定义和@var不同。例如,AAA是varchar(64),@var是bigint。这种情况下,非常有可能让本来是index seek的运算变成index scan,在大数据量表中,性能差距会非常明显。

从我的经验来看,并不是所有的隐式转换都会带来这样的问题。但是这样的问题大量的存在,并且在分析性能瓶颈、做索引调优时,会给你带来极大的困扰。必须分析缓存中查询计划对应的原始语句,看那玩意属于慢性自杀。

我们写SQL一般都会类型匹配,但是通过应用程序就非常容易出错。比方说一个表有个MobileNo字段用来存储手机号码,表中是varchar。但是应用程序你这么写:

SqlConnection conn = ...;

SqlCommand cmd = new SqlCommand("select * from Users where MobileNo = @mo", conn);

cmd.Parameters.Add(new SqlParameter("@mo", 13511223344));

SqlDataReader reader = cmd.ExecuteReader();

//....

那么你挂了……

到现在为止,我没有看到任何资料说哪种形式的隐式转换会让SQL无法判定结果集大小或者可以不去爬整棵索引树。所以我的建议是,使用最强类型去匹配查询列。查询列是啥,就写啥。是varchar(64)就别简单的new SqlParamerer(“@mo”, “13511223344”),要精确指定它的类型、长度。这样做有另外一个好处,偶将在下一篇blog——比较拼SQL、参数化SQL、使用存储过程执行DB指令的优劣时说明(btw:我相信那是一个好坑:))。

==加个总结=====================================
1、存储过程中,能不使用本地变量就不使用,尽可能的使用参数变量(也就是输入参数)。如果不得不使用本地变量,那也得只用在分布密度足够小的索引上使用。
2、写查询条件时,应该尽可能的使类型匹配。使用诸如SqlCommand执行DB指令时,一定要让输入参数从类型到长度严格匹配相应的列。尽管DB端不是所有的隐式转换都会引起性能损耗。
================================================

稍微提一句,在msdn中SQL Server Database Engine>Troubleshooting the Database Engine > Troubleshooting Queries下有一篇《Troubleshooting Poor Query Performance: Constant Folding and Expression Evaluation During Cardinality Estimation》,尽管说的粗糙无比外带模棱两可,但还是推荐一读。

写有效率的SQL查询(IV)相关推荐

  1. 写有效率的SQL查询(V)

    轉自:http://www.netfocus.cn/peoplearticle994.html 先站在应用程序的角度说说它们的不同. 1. 直接拼SQL 就像大家了解的那样,直接拼SQL带来了SQL注 ...

  2. 写有效率的SQL查询(I)

    大型系统的生产环境,一般情况下,我们评价一条查询是否有效率,更多的是关注逻辑IO(至于为什么,回头补一篇).我们常说,"要建彪悍的索引"."要写高效的SQL", ...

  3. 关于SQL查询效率,100w数据,查询只要1秒

    1.关于SQL查询效率,100w数据,查询只要1秒,与您分享: 机器情况 p4: 2.4 内存: 1 G os: windows 2003 数据库: ms sql server 2000 目的: 查询 ...

  4. SQL查询效率:100w数据查询只需要1秒钟

    机器情况 p4: 2.4 内存: 1 G os: windows 2003 数据库: ms sql server 2000 目的: 查询性能测试,比较两种查询的性能 SQL查询效率 step by s ...

  5. exists查询慢_8个SQL查询效率优化原则

    点击上方"Java秃头哥",选择"星标" 每天分享优质干货 1.对查询进行优化,应尽可能避免全表扫描 首先应考虑在 where 及 order by 涉及的列上 ...

  6. SQL查询优化方法 提高SQL查询效率 数据库的哪些字段适合添加索引

    如何提高sql的查询效率 在正确的字段上创建索引. 优化查询sql的写法(特别是where语句的写法). 一.数据库的哪些字段适合添加索引 表的某个字段值得离散度越高,该字段越适合选作索引的关键字.主 ...

  7. sql如何遍历几百万的表_关于SQL查询效率,100w数据,查询只要1秒

    1.关于SQL查询效率,100w数据,查询只要1秒,与您分享: 机器情况 p4: 2.4 内存: 1 G os: windows 2003 数据库: ms sql server 2000 目的: 查询 ...

  8. mysql 索引未命中_联合索引命中率问题导致SQL查询效率慢的问题

    执行 MySQL DumpSlow 结果是:Count: 1358  Time=0.33s (448s)  Lock=0.00s (0s)  Rows=2.5 (3343) Count:出现次数 Ti ...

  9. 一个 提高SQL 查询的讨论帖

    idn(关键字),产品名称,产品数量... B表,有字段:idn,a_idn(记录A表的关键字),工序,工时... A表与B表是一对多的关系, 我想取到A表的明细及B表相关的总工时 sele aa.* ...

最新文章

  1. 中国半导体最强助攻来了!十年免税、上下游一揽子扶持,明确「集成电路」为一级学科...
  2. 命令行打印文件树列表: tree
  3. 操作系统 : 按优先数调度算法实现处理器调度(C++)
  4. 云计算:大数据时代的系统工程
  5. map.setTerrain is not a function
  6. mac 2018 idea 无法 import导入或打开maven 项目
  7. Luogu5629 【AFOI-19】区间与除法
  8. python论文排版_学位论文排版教程1
  9. Android studio上音频文件格式问题
  10. IntelliJ IDEA更换主题样式分享
  11. 08、SpringCloud 系列:Nacos - 安装、启动
  12. Saliency Integration :An Arbitrator Model阅读总结
  13. Delphi XE6 原生解析json
  14. C++语言程序设计第五版 - 郑莉(第六章课后习题)
  15. 计算机英语及教学法,对高职计算机专业英语教学方法的探讨
  16. 打印机扫描功能不见了_打印机没有扫描选项怎么办
  17. Jetson TX2板载摄像头(一)
  18. css calc()函数 动态根据屏幕宽度计算宽度
  19. Windows10 打开SQL Server 配置管理器的方法
  20. python 统计检验_[转载]Python替代SPSS进行各项统计检验

热门文章

  1. MySQL定义条件和处理程序_MySQL教程111-MySQL定义条件和处理程序
  2. 如何判断 cxgrid 双击了哪一列_唐卡的价值主要体现在哪 如何判断唐卡的价值
  3. oracle glogin.sql sql _user,为什么我的login.sql不执行?
  4. java指定位置写入_java指定路径写、读文件
  5. 借助tkinter设计人脸检测的界面(摄像头检测,视频检测,视频检测并保存)
  6. HDU2141(二分查找)
  7. 思维dp ---- K步最短路 D. Explorer Space
  8. c 与matlab混编,谈谈Matlab与C/C++或C#的互调用(混合编程)
  9. 算法竞赛知识合集 目录(博客中转站)
  10. mysql rpc_使用XML-RPC和MySQL处理中文字符