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

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

尽量少用负向条件查询

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

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

select * from Order where Status != 0

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

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

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%'

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

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

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 != '小倩'

但结果是这样的

aaarticlea/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" data-ratio="0.20207253886010362" data-src="https://mmbiz.qpic.cn/mmbiz_jpg/tuSaKc6SfPrqwwm5MKPe3iaIicWXibqn4RPG0bDVv6DsShyGdDfZffX1VzqeXpOicq75ibcibfGkmrxerwe580VOSLQg/640" data-type="jpeg" data-w="193" />

那位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 * 的话,就会消耗大量无效的数据库内存。

SQL这样干,你就是给自己刨坑.....的更多相关文章

  1. RocketMQ事务消息学习及刨坑过程

    一.背景 MQ组件是系统架构里必不可少的一门利器,设计层面可以降低系统耦合度,高并发场景又可以起到削峰填谷的作用,从单体应用到集群部署方案,再到现在的微服务架构,MQ凭借其优秀的性能和高可靠性,得到了 ...

  2. 一次php访问sql server 2008的API接口的采坑

    2018年6月21日17:17:09,注意:不是详细文档,新手可能会看不懂 windows下安装 项目是sql server 2008的k3,php连接数据库写的API,因为是买的时候是别人的程序,测 ...

  3. Vue刨坑

    vue常见问题 1.在自定义组件里,你可以像任何普通元素一样用v-for.eg1: <my-component v-for="item in items"></m ...

  4. SQL SERVER CEILING 函数 取整时的坑。。。

    CEILING ---返回大于或等于指定数值表达式的最小整数 当舍去同一个大小的值 但是正负方向不一致时要注意小数位四舍五入的问题   例如: SELECT CEILING($123.45), CEI ...

  5. springboot+thymeleaf刨坑——首页加载js/css等失败解决方法

    在使用thymeleaf加载css或js样式,当我们进入登录页的时候发现,所有的样式都是加载失败的.原因是在新版中有这样一个坑……: 当我们设置了addInterceptors-注册拦截器的时候,通常 ...

  6. HAService 刨坑

    High availability is a characteristic of a system, which describes the duration (length of time) for ...

  7. vue刨坑(二)

    vue实例 vue实例 每一个应用都是通过vue这个构造函数创建根实例(root instance),启动 new vue(选项对象) 需要传入选项对象,对象包含挂载元素,数据,模板,方法等. el: ...

  8. 夜黑风高的夜晚用SQL语句做了一些想做的事·······

         IT这条漫漫长路注定是孤独的,陪伴我们的只有那些不知冷暖的代码语句和被手指敲打的磨掉了键上的标识的键盘. 之所以可以继续坚持下去,是因为心中有一份永不熄灭的激情. 成功的路上让我们为自己带盐 ...

  9. LINQ to SQL使用教程

    前些时间用LINQ to SQL做了一些项目,现在打算总结一下,帮助新手快速入门,并写一些别的教程没提到的东西. 一.LINQ to SQL和别的LINQ to XXX有什么关系?二.延迟执行(Def ...

随机推荐

  1. Web存储机制—sessionStorage,localStorage使用方法

    Web存储机制,在这里主要聊有关于Web Storage API提供的存储机制,通过该机制,浏览器可以安全地存储键值对,比使用cookie更加直观.接下来简单的了解如何使用这方面的技术. 基本概念 W ...

  2. vscode如何使用命令面板

    vscode如何使用命令面板 方法/步骤     首先找到vscode.   进入,打开页面.   找到查看.   打开找到命令面板.   选择打开,可以看到命令.   下拉还有多个,以及快捷键.   ...

  3. hearthbuddy中的Class276

    构造函数 需要注意的是this.intptr_0 = this.method_18("mono.dll"); 所以,这个类里面的操作,最后是和mono.dll相关的 interna ...

  4. jquery 复合事件 toggle()方法的使用

    定义和用法 toggle() 方法用于绑定两个或多个事件处理器函数,以响应被选元素的轮流的 click 事件. 语法: $(selector).toggle(function1(),function2 ...

  5. cookie、session的联系和区别,多台web服务器如何共享session

    1.Cookie与Session的联系: cookie在客户端保存状态,session在服务器端保存状态.但是由于在服务器端保存状态的时候,在客户端也需要一个标识,所以session也可能要借助coo ...

  6. Linux 安全工具之extundelete误删除恢复

    一:前言 在Linux中,我们通常会因为误删除文件而感到烦恼,rm -rf +文件  rf参数简直就是每个运维的噩梦,但是大家想过没,为什么删除文件那么快呢,为什么我们copy文件的时候那么慢. 其实 ...

  7. leetcode1281 整数的各位积和之差

    class Solution { public: int subtractProductAndSum(int n) { ; ; ){ ; n/=; prod*=r; add+=r; } int res ...

  8. 【React自制全家桶】四、React中state与props的分析与比较

    一.state 1.state的作用 state是React中组件的一个对象.React把用户界面当做是状态机,想象它有不同的状态然后渲染这些状态,可以轻松让用户界面与数据保持一致. React中,更 ...

  9. 使用ViewFlipper实现广告信息栏的上下翻滚效果

    import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Gestu ...

  10. IDEA "Library source does not match the bytecode for class"问题

    问题描述 Jar包更新后,报错信息:"Library source does not match the bytecode for class" 经检查,发现Jar内容还是旧版本的 ...