暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

开发中高质量MySQL技巧

健身程序员 2020-11-07
180

    总结开发中MySQL提升性能的一些小技巧。

下面例子参考这张表

    create table student(
    id int(11) not null AUTO_INCREMENT,
    user_id int(11) not null,
    name varhcar(255) default null,
    age int(3) default null,
    date datetime default null,
    set int(1) default null,
    primary key(id)
    KEY idx_userId(userId)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    复制

    一、查询中尽量用select 字段 代替 select *

       反例:

      select * from student; 
      复制

         正例:

        selec id,name from student;
        复制

        解析:

        • 只取需要的字段,节省资源、减少网络开销;

        • select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。

        二、如果知道查询结果条数,查询语句加上limit

        反例:

          select id,name from student where name='azb';
          复制

              正例:

            select id,name from student where name ='azb' limit 1;
            复制

            解析:

            • 加上limit 1后,只要找到了对应的一条记录,就不会继续向下扫描了,效率将会大大提高;

            • 当然,如果name是唯一索引的话,是不必要加上limit 1了,因为limit的存在主要就是为了防止全表扫描,从而提高性能,如果一个语句本身可以预知不用全表扫描,有没有limit ,性能的差别并不大。


            三、where后尽量避免or

                反例:

              select id,name from student where user_id=1 and name='azb';
              复制

              正例

                select id,name from student where user_id=1
                union all
                select id,name from student where name = 'azb';
                复制


                  select id,name from student where user_id=1;
                  select id,name from student where name = 'azb';
                  复制

                  解析:

                      使用or可能会导致索引失效,导致全表扫描

                  对于or+没有索引的name这种情况,假设它走了user_id的索引,但是走到name查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描+索引扫描+合并。

                  如果它一开始就走全表扫描,直接一遍扫描就完事。mysql是有优化器的,处于效率与成本考虑,遇到or条件,索引可能失效,看起来也合情合理。


                  四、优化limit分页查询

                      当我们用limit做分页查询时,当偏移量过大时,要采取优化措施。

                  反例:

                    select id,name from student limit 20000,8;
                    复制

                    正例1:返回上次查询的最大记录(偏移量)

                      select id,name from student where id>20000 limit 8;
                      复制

                      正例2:order by+索引

                        select id,name from student order by id limit 20000,8;
                        复制

                        正例3:在业务允许的情况下,限制页面数量。

                        解析:

                        • 当偏移量最大的时候,查询效率就会越低,因为Mysql并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的;

                        • 如果使用优化方案一,返回上次最大查询记录(偏移量),这样可以跳过偏移量,效率提升不少;

                        • 方案二使用order by+索引,也是可以提高查询效率的;

                        • 方案三的话,建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。


                        五、like语句的优化

                        反例:

                          select user_id,age from student where user_id like '%888';
                          复制

                          正例:

                            select user_id,age from student where user_id like '888%';
                            复制

                            解析:‘%’在前面,不走索引,放后面,走索引,所以开发时注意like用法,尽量不要导致索引失效。


                            六、索引上尽量不要使用内置函数,这样会导致索引失效。


                            七、不要where子句中对字段做表达式操作,这样会导致索引失效

                            反例:

                              select user_id,name from student where user_id-1 = 99;
                              复制


                              八、where子句尽量不要使用<>或!=,这样会导致索引失效。


                              九、left join,right join,inner join中尽量使用inner join ,如果使用left join,左边结果表尽量小。

                              解析:

                              • 如果inner join是等值连接,或许返回的行数比较少,所以性能相对会好一点;

                              • 同理,使用了左连接,左边表数据结果尽量小,条件尽量放到左边处理,意味着返回的行数可能比较少。


                              十、在使用联合索引时,要按顺序,一般是左匹配原则

                              上述示例表加入联合索引

                                KEY idx_userid_age (user_id,age) USING BTREE
                                复制

                                反例:

                                  select user_id,name from student where age=22;
                                  复制

                                  正例一:

                                    select user_id,name from student where user_id=111 and age=22;
                                    复制

                                    正例二:

                                      select user_id,name from student where user_id=111;
                                      复制

                                      解析:

                                      • 当我们创建一个联合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,这就是最左匹配原则;

                                      • 联合索引不满足最左原则,索引一般会失效,但是这个还跟Mysql优化器有关的。


                                      十一、数据量大时,可以where或order by涉及的字段上加索引。提高查询效率。


                                      十二、distinct

                                      解析:带distinct的语句cpu时间和占用时间都高于不带distinct的语句。因为当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较、过滤的过程会占用系统资源,cpu时间。


                                      十三、删除重复冗余索引

                                      解析:创建联合索引(M,N),就相当于创建了索引(M),(M,N),重复的索引需要维护,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能的。


                                      十四、优化大数据量的删除和修改语句。

                                          同时删除和修改大量的数据,会导致cpu负载过高,影响他人对数据的访问。

                                          反例:

                                        delete from sutdent where user_id <888888;
                                        复制

                                        正例一:

                                          //循环删除。放缓时间
                                          for(Student student:list){
                                             delete from student;
                                          }
                                          复制

                                          正例二:

                                            //分批进行删除
                                            delete student where id<500 
                                            delete student where id>=500 and id<1000
                                            复制

                                            解析:一次性删除太多数据,可能会有lock wait timeout exceed的错误,所以建议分批操作。


                                            十五、索引尽量不要建在有大量重复数据的字段上。

                                            解析:因为SQL优化器是根据表中数据量来进行查询优化的,如果索引列有大量重复数据,Mysql查询优化器推算发现不走索引的成本更低,很可能就放弃索引了。

                                            文章转载自健身程序员,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                            评论