最近一个朋友和我探讨关于Where 1=1 and这种形式的语句会不会影响性能。最后结论是不影响。算法
虽然结论正确,但对问题的认识却远远没有解决问题的根本。实际上在T-SQL语句的书写过程当中常常犯得错误就是得出一个很窄的结论,而后教条式的奉若圣经,对于T-SQL领域来讲,在网上常常能够看到所谓的优化守则,随便在网上搜了一些摘录以下:数据库
……….编程
虽然上述指导意见看上去没什么问题,也不能说彻底不正确,但实际上有两个重大问题:安全
脱离上下文:不少道理只能在一个上下文范围内生效,脱离了上下文范围就毫无心义。举个例子,日常有人对你说你有点肾虚,我想你的第一反应确定是想办法捍卫男人的尊严了,但若是你去医院检查医生这么说,那你可能就会一脸虔诚的求教如何补了:-),那举上述摘录的语句例子:1)少用子查询,若是在SQL Server操做XML的XPATH按节点属性筛选的时候,那转换成子查询必定会更快 2)若是使用了IN或者OR等时发现查询没有走索引,使用显式申明指定索引,这种状况查询分析器不走索引必定会有其缘由,编程语言
不解释本质缘由:佛语有云“凡全部相,皆是虚妄,若见诸相非相,即见如来”。请看下面故事:函数
说有一次两个府吏一块儿来看病,一个叫倪寻,一个叫李延,两人的症状也同样,都是头痛,身上发热,也许都是感冒吧。而华佗却说:“倪寻应当用下法来治,李延应当用汗法来治(寻当下之,延当发汗)。”旁人认为很奇怪,你们也必定认为很奇怪吧,为何一样的一个病,一样的症状,会有不一样的治疗法子呢?华佗解释了,他说:“倪寻是外实,而立延是内实,因此用了不一样的法子。”果真,次日,他们两的病都好了。性能
其实能够看出,彻底一样的症状,能够是彻底不一样的缘由,反之,一样的缘由,也能够造成彻底不一样的“相”。若是仅仅是看到“相”而采起应激处理措施,每每结果会不尽人意。优化
在每个领域都有其领域内的规则,最简单来讲,若是你不符合C#规范去编程,好比错误的使用关键字,那么编译就会报错。固然,每个领域内还会有一些隐藏的规则,也有人会说是所谓的“潜规则”,这类规则每每不在明面上,好比说你不符合最佳实践编写一段程序,编译不会报错,但所以而引发的性能或是安全性问题就是你须要遵循最佳实践这个“潜规则”才能避免。blog
而在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指数退让算法不是本文的重点,所以也很少讲了。