SQL这么写!你是给本身挖坑.....

sql.jpg
做者:会技术的葛大爷
原文:https://www.toutiao.com/i6606...程序员

SQL是做为一个程序员接触得很是多的一种语言,可是,不少时候,咱们会发现,有些SQL的执行效率异常的差,形成了数据库的负担。咱们经过分析这些有问题的SQL,就能够发现不少咱们平时在写SQL的时候忽略的问题。sql

今天,咱们就来说一下这些须要改掉的坏习惯。数据库

尽可能少用负向条件查询

==========函数

假设咱们有一个Order表,表中有一个字段是Status,这个字段有4个值,分别是0=待支付、1=待发货、2=待收货、3=已完成。优化

这时,咱们要查询全部已经支付的订单,不少人就会写这样的SQL:spa

select * from Order where Status != 0

这就是一个很差的习惯了。负向条件查询(例如:!=、not in、not exists)都是不能使用索引的,当Order表中的数据到达必定量级时,这个查询的效率会急剧的降低。设计

因此,正确的写法应该是:3d

select * from Order where Status in (1,2,3)
尽可能少用前导模糊查询

==========code

假设咱们如今要根据用户的订单号(OrderNo)查询用户的订单,若是是直接经过SQL查询的话,尽可能不要使用前导模糊查询,也就是:blog

select * from Order where OrderNo like '%param'

或者

select * from Order where OrderNo like '%param%'

由于,前导模糊查询是没法命中索引的,因此,会整个数据库去检索,效率至关的差,而非前导模糊查询则是可使用索引的。

所以,咱们尽可能不要把通配符放在前面,改为下面这样:

select * from Order where OrderNo like 'param%'

尽可能不要在条件字段上进行运算

==============

假设,如今有一个需求,是要查询2018年整年的订单数据,咱们就须要经过建立时间(CreateTime)来进行检索,可是,有些程序员就喜欢这样写SQL:

select * from Order where Year(CreateTime)=2018

而后,每次执行时就会发现,查询的速度异常的慢,致使了大量的请求挂起甚至超时。这是由于,咱们即便在CreateTime上创建了索引,可是,若是使用了运算函数,查询同样会进行全表的检索。

因此,咱们能够改为这样:

select * from Order where CreateTime > '2018-1-1 00:00:00'
当查询容许Null值的列时,须要特别注意

====================

咱们在建立表的字段时,若是这个字段须要做为索引时,尽可能不要容许Null。由于,单列索引不会存Null值,复合索引不存全部索引列都为Null的值,因此若是列容许为Null,可能会获得“不符合预期”的结果集。

例如:咱们有一个User表,其中有UserName字段记录了用户的名字,而且添加了索引。

如今咱们执行了这样一个查询:

select * from User where UserName != '小倩'

但结果是这样的

那位UserName为Null的数据并无能包括进来。所以,若是咱们想要包含这个用户的话,最好可以设置一个默认值。

复合索引,使用时要注意顺序

=============

登陆,确定是咱们使用得最多的一个查询了,为了保证效率,咱们为LoginID和Password加上了复合索引。

当咱们使用

select * from User where LoginID = '{LoginID}' and Password = '{Password}'  

select * from User where Password = '{Password}' and LoginID = '{LoginID}'

查询时,都是可以准备的命中索引。当咱们使用:

select * from User where LoginID = '{LoginID}'

查询时,也是可以命中索引的。可是,当咱们使用

select * from User where Password = '{Password}'

查询时,确没法命中索引,这是什么缘由呢?

这是因为,复合索引对于查询的顺序是很是的铭感的,因此,符合索引中包含了几种规则,其中就有全列匹配和最左前缀匹配。

当全部列都可以匹配时,虽然查询的顺序上有不一样,可是查询优化器会将顺序进行调整,以知足适合索引的顺序,因此,顺序的颠却是没有问题的。

可是,若是全部列不能匹配时,就必须知足最左前缀匹配了,也就是,必须按照从左到右的顺序进行排列。所以,当咱们创建是索引是<LoginID, Password>时,where Password = '{Password}' 就不知足最左前缀规则,没法命中索引了。

结果惟一时,别闷着

=========

一般,咱们设计User表时,并不会把LoginID做为主键,可是,LoginID确会在业务逻辑中验证惟一性,所以,若是使用

select * from User where LoginID = '{LoginID}'

查询时,结果必定只有一条。可是,数据库是不知道的,即便找到了这惟一的一条结果,他也会一直继续,直到扫描完全部的数据。

所以,在执行这样的查询时,咱们能够优化一下,改为:

select * from User where LoginID = '{LoginID}' limit 1

这样,当查询到结果时,就不会再继续了。

最后,上面全部的例子都是坑

=============

尽可能少用或别用Select ,咱们的查询其实都是有目的的,就好像登陆同样,咱们其实只须要知道有结果返回就好了,使用select count(0)就能够了,可是咱们使用select 的话,就会消耗大量无效的数据库内存。

相关文章
相关标签/搜索