SQL这样干,你就是给自己刨坑.....

简介: SQL是作为一个程序员接触得非常多的一种语言,但是,很多时候,我们会发现,有些SQL的执行效率异常的差,造成了数据库的负担。我们通过分析这些有问题的SQL,就可以发现很多我们平时在写SQL的时候忽略的问题。

SQL是作为一个程序员接触得非常多的一种语言,但是,很多时候,我们会发现,有些SQL的执行效率异常的差,造成了数据库的负担。我们通过分析这些有问题的SQL,就可以发现很多我们平时在写SQL的时候忽略的问题。

今天,我们就来讲一下这些需要改掉的坏习惯。

尽量少用负向条件查询

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

这时,我们要查询所有已经支付的订单,很多人就会写这样的SQL:

select * from Order where Status != 0

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

img_ea65a6741f86527d9784cdb1a6645719.jpe

所以,正确的写法应该是:

select * from Order where Status in (1,2,3)

尽量少用前导模糊查询

假设我们现在要根据用户的订单号(OrderNo)查询用户的订单,如果是直接通过SQL查询的话,尽量不要使用前导模糊查询,也就是:

select * from Order where OrderNo like '%param'

或者

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

因为,前导模糊查询是无法命中索引的,所以,会整个数据库去检索,效率相当的差,而非前导模糊查询则是可以使用索引的。

img_ae7b5caf9b09d7f3114cc594a0e78b7e.jpe

因此,我们尽量不要把通配符放在前面,改成下面这样:

select * from Order where OrderNo like 'param%'

img_8c5532954aed9aba42a781cb2f9e2a3e.jpe

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

假设,现在有一个需求,是要查询2018年全年的订单数据,我们就需要通过创建时间(CreateTime)来进行检索,但是,有些程序员就喜欢这样写SQL:

select * from Order where Year(CreateTime)=2018

然后,每次执行时就会发现,查询的速度异常的慢,导致了大量的请求挂起甚至超时。这是因为,我们即使在CreateTime上建立了索引,但是,如果使用了运算函数,查询一样会进行全表的检索。

img_665c62afca0ce7c923a8c563e4c8553b.jpe

所以,我们可以改成这样:

select * from Order where CreateTime > '2018-1-1 00:00:00'

当查询允许Null值的列时,需要特别注意

我们在创建表的字段时,如果这个字段需要作为索引时,尽量不要允许Null。因为,单列索引不会存Null值,复合索引不存所有索引列都为Null的值,所以如果列允许为Null,可能会得到“不符合预期”的结果集。

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

img_0c5a8670a48fa6510f163e12dcd3753e.jpe
img_7f68b15dc27b8c4fba6ff4c251a20890.jpe

现在我们执行了这样一个查询:

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

但结果是这样的

img_5d1d9b952875692786bf47b8fe66f261.jpe
img_824d1b0bb1b79cc143fbec16b513b822.jpe

那位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}'

查询时,确无法命中索引,这是什么原因呢?

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

当所有列都能够匹配时,虽然查询的顺序上有不同,但是查询优化器会将顺序进行调整,以满足适合索引的顺序,所以,顺序的颠倒是没有问题的。

img_80bba79577124373cf41b3d4ca87e7e9.jpe

但是,如果所有列不能匹配时,就必须满足最左前缀匹配了,也就是,必须按照从左到右的顺序进行排列。因此,当我们建立是索引是<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 * 的话,就会消耗大量无效的数据库内存。

img_ce1dcdb06eea73de3efc23692f5c0cc4.jpe

欢迎工作一到五年的Java工程师朋友们加入Java填坑之路:860113481

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

相关文章
|
11天前
|
SQL 分布式计算 运维
了解那些“奇葩”SQL写法,快速写出高效率SQL
本文主要讲解常见的SQL开发场景、‘奇葩’SQL写法并深入执行计划,带你了解如何快速写出高效率SQL。
|
10月前
|
SQL
面试官:我看你SQL语句掌握的怎么样?
面试官:我看你SQL语句掌握的怎么样?
66 1
面试官:我看你SQL语句掌握的怎么样?
|
6月前
|
SQL 存储 关系型数据库
21个写SQL的好习惯
21个写SQL的好习惯
55 1
|
6月前
|
SQL 分布式计算 MaxCompute
了解那些“奇葩”SQL写法,快速写出高效率SQL(4)
了解那些“奇葩”SQL写法,快速写出高效率SQL
38 0
了解那些“奇葩”SQL写法,快速写出高效率SQL(4)
|
6月前
|
SQL 分布式计算 MaxCompute
了解那些“奇葩”SQL写法,快速写出高效率SQL(1)
了解那些“奇葩”SQL写法,快速写出高效率SQL
51 0
了解那些“奇葩”SQL写法,快速写出高效率SQL(1)
|
6月前
|
SQL 分布式计算 运维
了解那些“奇葩”SQL写法,快速写出高效率SQL(3)
了解那些“奇葩”SQL写法,快速写出高效率SQL
53 0
了解那些“奇葩”SQL写法,快速写出高效率SQL(3)
|
6月前
|
SQL 分布式计算 MaxCompute
了解那些“奇葩”SQL写法,快速写出高效率SQL(2)
了解那些“奇葩”SQL写法,快速写出高效率SQL
32 0
了解那些“奇葩”SQL写法,快速写出高效率SQL(2)
|
SQL 存储 Oracle
工作中,我们经常用到哪些SQL语句呢?
工作中,我们经常用到哪些SQL语句呢?
182 1
工作中,我们经常用到哪些SQL语句呢?
|
SQL 存储 缓存
面试官:请分析一条SQL语句的执行
我感到在对全局了解不够清晰的时候,去深究一个知识点往往会事倍功半。所以打算通过这篇文章,分析SQL语句从头到尾的执行,串连一下MySQL当中的基础知识点。
98 0
面试官:请分析一条SQL语句的执行
|
SQL
SQL学习打卡第二天
select语句与where、group by、order by等子句结合使用
67 0