为什么SQL语句Where 1=1 and在SQL Server中不影响性能
最近一个朋友和我探讨关于Where 1=1 and这种形式的语句会不会影响性能。最后结论是不影响。
虽然结论正确,但对问题的认识却远远没有解决问题的根本。实际上在T-SQL语句的书写过程中经常犯得错误就是得出一个很窄的结论,然后教条式的奉若圣经,对于T-SQL领域来说,在网上经常可以看到所谓的优化守则,随便在网上搜了一些摘录如下:
- 不要有超过5个以上的表连接(JOIN)
- 考虑使用临时表或表变量存放中间结果
- 少用子查询
- 视图嵌套不要过深,一般视图嵌套不要超过2个为宜。
- 对出现在where子句中的字段加索引
- 避免在索引列上使用函数或计算,在where子句中,如果索引是函数的一部分,优化器将不再使用索引而使用全表扫描
- 在insert和update维表时都加上一个条件来过滤维表中已经存在的记录
- 如果使用了IN或者OR等时发现查询没有走索引,使用显式申明指定索引
- EXISTS要远比IN的效率高。
……….
问题出在哪了?
虽然上述指导意见看上去没什么问题,也不能说完全不正确,但实际上有两个重大问题:
脱离上下文:很多道理只能在一个上下文范围内生效,脱离了上下文范围就毫无意义。举个例子,平常有人对你说你有点肾虚,我想你的第一反应肯定是想办法捍卫男人的尊严了,但如果你去医院检查医生这么说,那你可能就会一脸虔诚的求教如何补了:-),那举上述摘录的语句例子:1)少用子查询,如果在SQL Server操作XML的XPATH按节点属性筛选的时候,那转换成子查询一定会更快 2)如果使用了IN或者OR等时发现查询没有走索引,使用显式申明指定索引,这种情况查询分析器不走索引一定会有其原因,
不解释本质原因:佛语有云“凡所有相,皆是虚妄,若见诸相非相,即见如来”。请看下面故事:
说有一次两个府吏一起来看病,一个叫倪寻,一个叫李延,两人的症状也一样,都是头痛,身上发热,也许都是感冒吧。而华佗却说:“倪寻应当用下法来治,李延应当用汗法来治(寻当下之,延当发汗)。”旁人认为很奇怪,大家也一定认为很奇怪吧,为什么同样的一个病,同样的症状,会有不同的治疗法子呢?华佗解释了,他说:“倪寻是外实,而立延是内实,所以用了不同的法子。”果然,第二天,他们两的病都好了。
其实可以看出,完全同样的症状,可以是完全不同的原因,反之,同样的原因,也可以形成完全不同的“相”。如果仅仅是看到“相”而采取应激处理措施,往往结果会不尽人意。
Think Like Query Optimizer
在每一个领域都有其领域内的规则,最简单来说,如果你不符合C#规范去编程,比如错误的使用关键字,那么编译就会报错。当然,每一个领域内还会有一些隐藏的规则,也有人会说是所谓的“潜规则”,这类规则往往不在明面上,比如说你不符合最佳实践编写一段程序,编译不会报错,但因此而引起的性能或是安全性问题就是你需要遵循最佳实践这个“潜规则”才能避免。
而在SQL Server领域,T-SQL语句到查询结果返回需要经历一个完整的周期,如图1:
图1.T-SQL生命周期
因此,在关系数据库领域,SQL语句的写法只是一个抽象的逻辑,而不是像编程语言那样直接的实现。比如说访问一行数据,如果是编程语言实现,就需要指定连接数据的方式,打开数据,按某个方式取出数据,最后还要关闭连接,而在SQL Server中,T-SQL仅仅是定义如何去获取所需的数据,而无需考虑实现细节。
图1中从T-SQL到具体返回数据经历了多个步骤,每一个步骤又存在大量的规则。因此在本文提到Where 1=1 and引起的性能问题就需要按照查询分析器的规则去考虑为什么,这也是Think like query optimizer。
在SQL Server中,T-SQL需要编译为执行计划才能去执行,在编译过程中,Query Optimizer需要考虑很多元数据,比如说表上的索引、数据分布、估计行数、一些参数配置、硬件环境等,在这其中,最重要的就是估计行数,SQL Server需要估计行数来估计成本。
Where 1=1 and写法为什么不会变慢?
因为查询分析器在代数树优化阶段就把1=1 直接给过滤掉了。这个功能就是查询优化器中所谓的“Constant Folding”。
我们这里假设查询分析器在代数树优化阶段没有把where 1=1这种情况直接过滤掉。
比如语句select * from table where a=1 and b=2 这个语句,SQL Server估计的行数会是:
a列的选择率*b列的选择率*表中采样的总行数
因此,当Where 1=1 and a=1时,结果就变为
1*a列的选择率 *表中采样的总行数=a列的选择率 *表中采样的总行数
因此无论是否有1=1 and,查询分析器都会估计相同的行数,从而拥有同样的执行计划,因此不影响性能。
当我们明白了查询分析器对A and B这种写法是如何估计行数之后,那么我们就可以推算出什么情况A and B可能引起执行计划不准确。从公式来看,SQL Server认为A列和B列是无关联的,如果A和B关联很大,那么估计的行数一定会非常不准。
这里我们举例,假如表中有100万行数据,where a=1的数据有1万条,where b=1的数据有1万条,则A和B的选择性都是1/100=0.01,在Where中A And B联合的估计行数则变为0.01*0.01=0.0001*100万=100行,假设where a=1 和b=1所筛选的数据为同样的1万行数据,则估计行数为100而实际行数为1万,则可能引起执行计划的不准确,从而引起性能问题。当然,这种情况的确是少数,但发生后往往对性能有一定影响,因此SQL Server 2014新的行数估计采用了指数退让算法,在这种情况下就会估计为1000行,从而引起性能问题的可能性会变小,2014指数退让算法不是本文的重点,因此也不多讲了。
为什么SQL语句Where 1=1 and在SQL Server中不影响性能的更多相关文章
- C# sql语句拼接时 like情况的防sql注入的用法
今天下午同事问我一个比较基础的问题,在拼接sql语句的时候,如果遇到Like的情况该怎么办. 我原来的写法就是简单的拼接字符串,后来同事问我如果遇到sql注入怎么办.我想了下,这确实是个问题. 刚在网 ...
- mybatis 的sql语句及使用mybatis的动态sql mybatis防注入
由于看到写的比较详细的文档这里将之前的删掉了,只留下一些我认为能帮助理解的和关于动态sql及防注入的一些理解.文档链接 :mybatis官方文档介绍 <!-- 根据条件查询用户 --> ...
- mysql通过sql语句判断某个字段在一张表中是否存在
应用场景: 我有一张表,表里面都是用户用来激活游戏的激活码,当用户在前端页面输入激活码时,要查询数据表中是否有这条激活码,如果有就返回"1",没有则返回"0". ...
- 一条sql语句搞定基于mysql的sql执行顺序的基本理解
对数据库基本操作是每个程序员基本功,如何理解并快速记住sql执行的顺序呢,其实一条复杂的sql就能搞定: SELECT DISTINCT <select_list> FROM <le ...
- [mybatis] sql语句无错误,但是执行多条sql语句时,抛出java.sql.SQLSyntaxErrorException
错误内容 org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: java.sql.S ...
- sql语句联表更新(从一个数据库中的一张表更新到另一个数据库的另一张表)
一.sql server数据库写法: update a set a.ksgmm=b.ksgmm,a.ksgm=b.ksgm,a.scztm=b.scztm,a.sczt=b.sczt from lan ...
- SpringBoot:阿里数据源配置、JPA显示sql语句、格式化JPA查询的sql语句
1 数据源和JPA配置 1.1 显示sql配置和格式化sql配置 者两个配置都是属于hibernate的配置,但是springdatajpa给我们简化了:所有hibernate的配置都在jpa下面的p ...
- 在使用sql语句的一些注意事项(sql语句)
版权声明:本文为博主原创文章,未经博主允许不得转载. 原文地址: https://www.cnblogs.com/poterliu/p/4925483.html ①如果插入字段包含对应的表的所有字段, ...
- 使用sqlparse分析SQL语句,及自己写的SQL分析语句
备忘, 以后写的时候可以参考. #!/usr/bin/env python # -*- coding: utf-8 -*- import sqlparse import re sql = " ...
随机推荐
- cowboy学习笔记(安装与部署)
安装cowboy,参照官方文档:http://ninenines.eu/docs/en/cowboy/1.0/guide/getting_started/ 添加依赖库:在makefile中添加,会自动 ...
- SAP SLT (Landscape Transformation) 企业定制培训
No. Item Remark 1 SAP SLT概述 SAP Landscape Transformation Overview 2 SAP SLT 安装与配置<1> for abap ...
- iOS7界面的兼容性调整之一
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) { self.edgesForExtendedLayout ...
- windows下安装iReport 并确保启动正确
突然从润乾转到iReport ,我也很蒙.突然离开了万能的客服,我心不甘.现在所有资料都要自己查找,只好做个记录.现在从安装开始说. 此时安装的最新版是5.6.0,要知道,网上大部分资料都是4.X,更 ...
- day14---html基础
本节内容: 一.HTML 二.CSS 三.JS HTML 1.一套规则,浏览器认识的规则. 2.开发者: 学习Html规则 开发后台程序: - 写Html文件(充当模板的作用) ****** - 数据 ...
- Centos普通用户提权至ROOT
1.利用/bin/ping的漏洞普通用户提权.(rws中的s) [root@localhost ~]# ls -l /bin/ping -rwsr-xr-x. root root 9月 /bin/pi ...
- cocos2d-x 2.2.2 android平台移植
1.完成以上工具的下载安装--cocos2d-x 2.2.2 --eclipse+adt+sdk --ndk 2.创建cocos2d-x工程 在"cocos2d-x-2.2.2\tools\ ...
- Asp.net web form url route使用总结
asp.net web form 使用URL路由 注不是mvc中的路由 一.前台控件使用路由,通过表达式生成url地址,注意给路由参数赋值,防止使用了其他路由表达式值方式1:<asp:Hyper ...
- C#的函数柯里化
前面说到了C#的泛型委托和闭包函数,在函数是程序设计里还有一个重要特征是柯里化... 柯里化就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结 ...
- 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d3e3ab10c62013697408 作者:黄宁源 一,背景 Recy ...