在每一个消耗大量时间的查询中,都能看到一些不必要的额外操作、某些操作被额外地重复了很多次、某些操作执行得太慢等。优化查询的目的就是减少和消除这些操作所花费的时间。
查询性能低下最基本的原因是访问的数据太多。所以需要考虑是否向数据库请求了不需要的数据
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