在每一个消耗大量时间的查询中,都能看到一些不必要的额外操作、某些操作被额外地重复了很多次、某些操作执行得太慢等。优化查询的目的就是减少和消除这些操作所花费的时间。

查询性能低下最基本的原因是访问的数据太多。所以需要考虑是否向数据库请求了不需要的数据


1、多表关联时,或获取单表数据时,尽量避免不加思考地使用SELECT *

      从数据库里读出的数据越多,查询就会越慢。每次查询考虑好需要取出的列,需要什么取出什么

2、当需要一条数据时,记得limit1

      例如在处理分页时,应该使用LIMIT限制MySQL只返回需要的数据,而不是向应用程序返回全部数据后,再由应用程序过滤不需要的行。

3、使用缓存,减少查询请求

      当一些数据被多次使用时可以考虑将数据缓存起来,避免每次使用都要到MySQL查询。例如可以使用redis、memcache等

4、为搜索字段添加索引

      索引不一定就是给主键或者是唯一的字段,如果在表中,有某个字段经常用来做搜索,需要将其建立索引。

      详细有关索引学习可以查看  https://www.w3cschool.cn/mysql/mysql-index.html

5、不要使用ORDER BY RAND()

      MySQL去执行RAND()函数(很耗CPU时间),而且这是为了每一行记录去记行,然后再对其排序。就算是你用了Limit 1也无济于事(因为要排序) 。如果你真的想把返回的数据行打乱了,你有多种其他方法可以达到这个目的。这样使用只让你的数据库的性能呈指数级的下降。

6、为每张表设置一个ID主键

    我们应该为数据库里的每张表都设置一个ID做为其主键,而且最好的是一个INT型的,并设置上自动增加的 AUTO_INCREMENT标志。

7、尽量为字段固定长度

      例如varchar、text等字段类型。虽然不固定长度可以节约空间,但是每一次查询更耗费时间。固定长度的表会提高性能,因为MySQL搜寻得会更快一些,因为这些固定的长度是很容易计算下一个数据的偏移量的,所以读取的自然也会很快。而如果字段不是定长的,那么,每一次要找下一条的话,需要程序找到主键。 并且,固定长度的表也更容易被缓存和重建。

8、选择正确的存储引擎

      mysql中有不同的存储引擎,其中有MyISAM  和 InnoDB 。每个引擎都要他的利弊。

     MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。

     InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。

9、使用EXPLAIN关键字检测查询

      使用EXPLAIN关键字可以使我们知道MySQL是如何处理SQL语句的,这样可以帮助我们分析我们的查询语句或是表结构的性能瓶颈。

10、尽量避免SQL中出现运算

      例如select a+5 from A,让DB功能单一化

11、设计表的时候尽量用”小数据类型”,比如尽量避免text,blob等这些大家伙,优先使用ENUM和SET

12、设计表字段能用数字类型就千万别用字符类型,比如存IP地址,用int,别用varchar

13、尽量避免null字段

        定义时尽量使用 not null.原因是允许null时不方便查询优化,复合索引也会失效,而且如果列有索引时会额外占用空间

14、避免 “% 前缀” 或者 “%内容%” 模糊查询

         因为会导致索引失效,大数据量下是灾难

15、在做分页查询时,避免 limit 1000000,100    

        这种分页查询方式会从数据库第一条记录开始扫描,所以越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度。可以使用子查询优化id限定优化(参考w3cschool)

使用子查询优化

这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。

select * from orders_history where type=8 limit 100000,1;

select id from orders_history where type=8 limit 100000,1;

select * from orders_history where type=8 and 
id>=(select id from orders_history where type=8 limit 100000,1) 
limit 100;

select * from orders_history where type=8 limit 100000,100;

4条语句的查询时间如下:

     第1条语句:3674ms     第2条语句:1315ms     第3条语句:1327ms     第4条语句:3710ms

针对上面的查询需要注意:

    1、比较第1条语句和第2条语句:使用 select id 代替 select * 速度增加了3倍

    2、比较第2条语句和第3条语句:速度相差几十毫秒

    3、比较第3条语句和第4条语句:得益于 select id 速度增加,第3条语句查询速度增加了3倍

这种方式相较于原始一般的查询方法,将会增快数倍。

使用 id 限定优化

这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询:

select * from orders_history where type=2 
and id between 1000000 and 1000100 limit 100;

查询时间:15ms 12ms 9ms

这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况,不过一般建立表的时候,都会添加基本的id字段,这为分页查询带来很多遍历。

还可以有另外一种写法:

select * from orders_history where id >= 1000001 limit 100;

详细关于分页查询优化可以参考  https://www.w3cschool.cn/mysql/mysql-xilz2oy6.html