Mysql分页查询优化

目录

1.插入大量数据(批处理)

(1). 插入相同的数据:

(2).插入不同的数据:

2. 分页查询大数据量效率低

3.分页查询优化:



1.插入大量数据(批处理)

(1). 插入相同的数据:

创建存储过程,向表中插入大量数据

drop procedure if EXISTS `my_procedure`; 
delimiter //
create procedure my_procedure()
BEGIN
  DECLARE n int DEFAULT 1;
  #关闭自动提交,否则insert一次,则提交一次事务,严重降低性能,我们关系自动提交,使用批处理,整个过程只提交一次事务。
  SET autocommit = 0;
  WHILE n < 10001 DO
    insert INTO weather (city,shidu,pm25,pm10,quality,high_temp,low_temp) VALUE ('Qingdao','20%',50,60,'good',29,21); 
    set n = n + 1;
  END WHILE;
  COMMIT; #提交事务,一次性提交
END
delimiter ;  #恢复以分号做为一行的结束

执行的时候报错(单独执行第一句,就报出如下错误),怀疑是因为当前用户没有足够的权限。

授予用户权限:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY '123456' WITH GRANT OPTION;  

但是加了权限之后仍然不行, 于是参考了这篇文章:MYSQL中创建存储过程实现向表中循环插入数据_sunstubble的博客-CSDN博客_mysql 存储过程 插入

发现是因为存储过程开始的时候,"delimiter //",意思是mysql语句的结尾换成以  // 结束,mysql默认是;结束。这样的话,存储过程结束的时候,要加'//', 修改成下面的代码:

DELIMITER // /*(意思是mysql语句的结尾换成以 //  结束,mysql默认是;结束)*/

create procedure my_procedure()
BEGIN
  DECLARE n int DEFAULT 1;
  #关闭自动提交,否则insert一次,则提交一次事务,严重降低性能,我们关系自动提交,使用批处理,整个过程只提交一次事务。
  SET autocommit = 0;
  WHILE n < 10001 DO
    insert INTO weather (city,shidu,pm25,pm10,quality,high_temp,low_temp) VALUE ('Qingdao','20%',50,60,'good',29,21); 
    set n = n + 1;
  END WHILE;
  COMMIT; #提交事务,一次性提交
END 
//      /*存储过程结束, 要以//做为结束标记*/

DELIMITER ; #恢复以分号做为一行的结束

创建存储过程成功之后,执行存储过程, 数据插入成功。

(2).插入不同的数据:

上述创建的存储过程,插入的数据都是相同的,如果想插入不同的数据呢?

需要创建函数,函数返回随机值,做为insert的value值。

创建两个function : rand_string(n INT)产生随机字符串, rand_num()创建随机数字。

 然后创建存储过程,插入数据,其中要用到function的返回值,做为value值。

 然后执行存储过程, 插入10条部门数据(根据自己需要进行设置,比如50000),部门编号从100开始。

DELIMITER ;

CALL insert_dept(100,10); 

 插入的数据如下:

2. 分页查询大数据量效率低

mysql大数据量使用limit分页,随着页码的增大,查询效率越低下,因为分页查询是全表查询,然后从查询出的记录中再获取分页数据。

SELECT * FROM weather LIMIT start, pageSize;
(1).起始页较小时,查询是没有性能问题的,分别从10, 100, 1000, 10000开始分页的执行时间(每页取10条)如下:
select * from weather limit 10, 10   0.016秒
select * from weather limit 100, 10   0.016秒
select * from weather limit 1000, 10   0.047秒
select * from weather limit 10000, 10   0.094秒
可以看出,随着起始记录的增加,时间也随着增大, 这说明分页语句limit跟起始页码是有很大关系的,

(2).上面的查询效率还可以接受,但是我们把起始记录改为40w看下。

select * from product limit 400000, 10   3.229秒
(3).如果起始记录再大呢?显然这种时间是无法忍受的。
select * from product limit 900000, 10   37.44秒
从中我们总结出两件事情:

  1. limit语句的查询时间与起始记录的位置成正比
  2. mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。

3.分页查询优化:

好视频:【IT老齐074】从76237到753毫秒,海量数据大页码MySQL查询该如何优化?_哔哩哔哩_bilibili

既然分页查询有这样的问题,那么能够对其进行优化呢?当然可以,利用表的覆盖索引来加速分页查询。
覆盖索引所要查询(select)的字段和where条件都只用建立了索引的字段,只在索引中查询就能完成查询工作,不用回表查询,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。
在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何:
select id from weather limit 900000, 10 0.2秒
只查询建立了索引的列id(覆盖索引),这相对于查询了所有列的37.44秒,提升了大概100多倍的速度。
那么如果我们也要查询所有列,有三种方法(其实都是利用了子查询):

(1).一种是id>=的形式(必须是id连续的情况???)。
SELECT * FROM weather WHERE id >=(select id from weather limit 900000, 1) limit 10
查询时间为0.2秒,质的飞跃。子查询用了主键索引,父查询也用了主键索引。
(2).另一种就是利用join(连接查询)(必须是id连续的情况???)。
SELECT * FROM weather a JOIN (select id from weather limit 900000, 10) b ON a.id = b.id

子查询用了主键索引,父查询也用了主键索引。

*通配符在实际的查询中最好不使用,应该指明相应的属性,效率更高。

(3).复合索引。

上面的例子如果加上where语句,会怎么样呢?

select id from weather where vtype=1 order by id limit 900000,10; 看看结果,时间是10秒!

因为vtype字段不在索引中,所以查询效率又降低了。

建立一个search(vtype,id) 这样的索引,再执行查询语句(这里不光是能够通过索引查询,另外还覆盖索引):

select id from weather where vtype=1 order by id limit 90000,10; 非常快!0.04秒完成!

总结:如果对于有where 条件,又想走索引的,必须设计一个索引,将where 语句中用到的字段放第一位,limit用到的主键放第2位。

其实三者用的都是一个原理,所以效果也差不多

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值