zoukankan      html  css  js  c++  java
  • MySQL优化2之SQL常用技巧

    1、SQL语句中IN包含的值不应过多

    IN中如果数值较多,产生的消耗会比较大的。再例如:select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了;再或者使用连接来替换。

    2、SELECT语句务必指明字段名称

    SELECT *增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前断也需要更新。所以要求直接在select后面接上字段名。

    3、当只需要一条数据的时候,使用limit 1

    这是为了使EXPLAIN中type列达到const类型

    4、如果排序字段没有用到索引,就尽量少排序

    5、如果限制条件中其他字段没有索引,尽量少用or

    or两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果

    6、尽量用union all代替union

    UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

    Union:对两个结果集进行并集操作,去除重复行,同时进行默认规则的排序(增加了对CPU的消耗);

    Union All:对两个结果集进行并集操作,包括重复行,不进行排序;

    7、 in和exists

    如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in;

    例如:表A(小表),表B(大表)  尽量让大表走索引

    select * from A where cc in(select cc from B)  -->效率低,用到了A表上cc列的索引;

    select * from B where cc in(select cc from A)  -->效率高,用到了B表上cc列的索引

    select * from A where exists(select cc from B where cc=A.cc)  -->效率高,用到了B表上cc列的索引。

    select * from B where exists(select cc from A where cc=B.cc)  -->效率低,用到了A表上cc列的索引。

    8、not in 和not exists

    not in 逻辑上不完全等同于not exists,not in可能存在逻辑问题,会导致程序存在致命的问题,比如:

    create table #t1(c1 int,c2 int);

    create table #t2(c1 int,c2 int);

    insert into #t1 values(1,2);

    insert into #t1 values(1,3);

    insert into #t2 values(1,2);

    insert into #t2 values(1,null);

    select * from #t1 where c2 not in(select c2 from #t2);  -->执行结果:无

    select * from #t1 where not exists(select 1 from #t2 where #t2.c2=#t1.c2) -->执行结果:1  3

    另外如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;

    而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。

    9、使用合理的分页方式以提高分页的效率

    select id,name from product limit 866613, 20

    使用上述sql语句做分页的时候,可能有人会发现,随着表数据量的增加,直接使用limit分页查询会越来越慢。

    优化的方法如下:可以取前一页的最大行数的id,然后根据这个最大的id来限制下一页的起点。比如此列中,上一页最大的id是866612。sql可以采用如下的写法:

    select id,name from product where id> 866612 limit 20

    10、分段查询

    在一些用户选择页面中,可能一些用户选择的时间范围过大,造成查询缓慢。主要的原因是扫描行数过多。这个时候可以通过程序,分段进行查询,循环遍历,将结果合并处理进行展示。扫描的行数成百万级以上的时候就可以使用分段查询

    11、避免在 where 子句中对字段进行 null 值判断

    对于null的判断会导致引擎放弃使用索引而进行全表扫描。

    12、不建议使用%前缀模糊查询

    例如LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。

    怎么查询%name%?虽然给查询字段添加了索引,但在explain结果果并没有使用

    那么如何解决这个问题呢,答案:使用全文索引

    在我们查询中经常会用到select id,fnum,fdst from dynamic201606 where username like '%zhangsan%'; 。这样的语句,普通索引是无法满足查询需求的。庆幸的是在MySQL中,有全文索引来帮助我们。

    创建全文索引的sql语法是:

    ALTER TABLE `dynamic_201606` ADD  FULLTEXT INDEX  `idx_user_name` (`user_name`);

    使用全文索引的sql语句是:

    select id,fnum,fdst from dynamic_201606 where match(user_name) against('zhangsan' in boolean mode);

    注意:查询语句的写法与普通索引的区别

    13、避免在where子句中对字段进行表达式操作

    比如select user_id,user_project from user_base where age*2=36;

    中对字段就行了算术运算,这会造成引擎放弃使用索引,建议改成

    select user_id,user_project from user_base where age=36/2;

    14、避免隐式类型转换

    where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换,建议先确定where中的参数类型;

    比如:传入参数为integer,  而实际上表中no列为varchar类型,此时会导致no上的索引失效。

    select id,name,careatetime from t1 where no=123

    15、对于联合索引来说,要遵守最左前缀法则

    举列来说索引含有字段id,name,school,可以直接用id字段,也可以id,name这样的顺序,但是name;school都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面

    16、必要时可以使用force index来强制查询走某个索引

    有的时候MySQL优化器采取它认为合适的索引来检索sql语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用force index来强制优化器使用我们制定的索引。

    17、注意范围查询语句

    对于联合索引来说,如果存在范围查询,比如between,>,<等条件时,会造成后面的索引字段失效。

    18、关于JOIN优化

     

    LEFT JOIN A表为驱动表

    INNER JOIN MySQL会自动找出那个数据少的表作用驱动表

    RIGHT JOIN B表为驱动表

    尽量使用inner join,避免left join

    参与联合查询的表至少为2张表,一般都存在大小之分。如果连接方式是inner join,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表,但是left join在驱动表的选择上遵循的是左边驱动右边的原则,即left join左边的表名为驱动表。

    合理利用索引

    被驱动表的索引字段作为on的限制字段。

    利用小表去驱动大表

    如果能够减少驱动表的话,减少嵌套循环中的循环次数,以减少 IO总量及CPU运算的次数。

    巧用STRAIGHT_JOIN

    inner join是由mysql选择驱动表,但是有些特殊情况需要选择另个表作为驱动表,比如有group by、order by等「Using filesort」、「Using temporary」时。STRAIGHTJOIN来强制连接顺序,在STRAIGHTJOIN左边的表名就是驱动表,右边则是被驱动表。在使用STRAIGHTJOIN有个前提条件是该查询是内连接,也就是inner join。其他链接不推荐使用STRAIGHTJOIN,否则可能造成查询结果不准确。

  • 相关阅读:
    SQL Azure (17) SQL Azure V12
    Microsoft Azure News(5) Azure新DV2系列虚拟机上线
    Azure Redis Cache (3) 在Windows 环境下使用Redis Benchmark
    Azure PowerShell (11) 使用自定义虚拟机镜像模板,创建Azure虚拟机并绑定公网IP(VIP)和内网IP(DIP)
    Windows Azure Virtual Machine (31) 迁移Azure虚拟机
    Windows Azure Web Site (16) Azure Web Site HTTPS
    Azure China (12) 域名备案问题
    一分钟快速入门openstack
    管理员必备的Linux系统监控工具
    Keepalived+Nginx实现高可用和双主节点负载均衡
  • 原文地址:https://www.cnblogs.com/brant/p/12819744.html
Copyright © 2011-2022 走看看