SQL是作为程序员接触比较多的一门语言。但是很多时候,我们会发现某些SQL的执行效率异常的差,从而给数据库造成了负担。.通过分析这些有问题的SQL,我们可以发现很多我们在编写SQL时通常会忽略的问题。今天,我们就来说说这些需要改掉的坏习惯。尽量使用尽可能少的否定条件查询。假设我们有一个订单表。表中有一个名为Status的字段。该字段有4个值,即0=待付款,1=待发货,2=待收货,3=已完成。这时候我们要查询所有已经支付的订单,很多人会写这样的SQL:select*fromOrderwhereStatus!=0,这是一个坏习惯。否定条件查询(例如:!=、notin、notexists)不能使用索引。当Order表中的数据达到一定程度时,这个查询的效率就会急剧下降。因此,正确的写法应该是:select*fromOrderwhereStatusin(1,2,3)尽量少用leadingfuzzyquery。假设我们要根据用户的订单号(OrderNo)查询用户的订单。如果是直接通过SQL查询,尽量不要使用前导模糊查询,即:select*fromOrderwhereOrderNolike'%param'或者select*fromOrderwhereOrderNolike'%param%'因为不能对前导模糊查询进行索引,所以整个数据库会查找,效率比较差,非前导模糊查询可以使用索引。因此,我们尽量不要把通配符放在前面,改成如下:select*fromOrderwhereOrderNolike'param%'尽量不要对条件字段进行操作。假设,现在有一个需求,查询2018年全年的订单数据,我们需要通过创建时间(CreateTime)来查找,但是有些程序员喜欢这样写SQL:select*fromOrderwhereYear(CreateTime)=2018然后,每执行一次,就会发现查询速度异常缓慢,导致大量请求挂起,甚至超时。这是因为,即使我们在CreateTime上创建了索引,如果使用操作函数,查询也会搜索整张表。因此,我们可以改成这样:select*fromOrderwhereCreateTime>'2018-1-100:00:00'在查询允许Null值的列时,需要特别注意我们在建表时创建的字段,如果这个字段需要作为索引使用,尽量不允许为Null。因为单列索引不存储Null值,而复合索引不存储所有索引列的Null值,所以如果允许列为Null,则可能会得到“意外”的结果集。比如:我们有一个User表,它有一个UserName字段,记录了用户的名字,并添加了一个索引。现在我们执行了这样一条查询:select*fromUserwhereUserName!='Xiaoqian'但结果是没有包含UserName为Null的数据。因此,如果我们想包含这个用户,可以设置一个默认值。复合索引,使用的时候注意login的顺序,一定是我们用的最多的query,为了保证效率,我们添加了LoginID和Password的复合索引。当我们使用select*fromUserwhereLoginID='{LoginID}'andPassword='{Password}'select*fromUserwherePassword='{Password}'andLoginID='{LoginID}'进行查询时,是可以准备的最好的索引。当我们使用:select*fromUserwhereLoginID='{LoginID}'查询时,也是能够***索引的。但是,当我们使用select*fromUserwherePassword='{Password}'进行查询时,是无法激活索引的。是什么原因?这是因为复合索引对查询的顺序非常敏感,所以它匹配索引包含几种规则,包括全列匹配和最左前缀匹配。当所有的列都可以匹配的时候,虽然查询的顺序不同,但是查询优化器会调整顺序来满足适合索引的顺序,所以顺序倒置是没有问题的。但是,如果所有的列都不能匹配,则必须满足最左边的前缀匹配,即必须从左到右依次排列。因此,当我们创建一个唯一结果的索引时,不要无聊。通常我们在设计User表的时候,不会把LoginID作为主键,但是LoginID在业务逻辑中确实会校验唯一性。因此,如果你使用select*fromUserwhereLoginID='{LoginID}'查询时,肯定只有一个结果。但是,数据库并不知道,即使找到了唯一的结果,它也会继续下去,直到扫描完所有数据。因此,在执行这样的查询时,我们可以优化一下,改成:select*fromUserwhereLoginID='{LoginID}'limit1。这样,当得到查询结果时,就不再继续了。***,以上例子都是坑尽量少用或者不用Select*。我们的查询其实是有目的的,就像登录一样,其实我们只需要知道有结果返回即可。使用selectcount(0)是可以的,但是如果我们使用select*,就会消耗大量无效的数据库内存。
