业务-(导出速度优化)的实现与原理分析

这篇文章分享一下一个sql查询优化方案:where+limit避免对无用数据的访问(避免全表扫描),这样可以减少访问表的次数,提高查询效率。

limit的两种用法:

1.limit m //从结果集中取出前m条返回

2.limit m,n //从结果集的第m条数据开始,返回n条数据

其中第2种在结果集数据量非常大的时候效率就显得不那么高了,因为无论最后返回多少条数据,数据库还是要查询m+n次,只是截取了前m条结果丢弃了而已。

既然前m条数据都是无用的,那么如何使数据库可以避免查询这m条数据呢?

这个可以根据业务场景的不同采取对应的措施,比如下面这个导出速度过慢的问题:

 业务场景:

一个界面的货品货位数据导出14万条数据10分钟导出了2%,速度太慢。

技术背景:

导出数据的逻辑操作是底层封装的,导出的数据是通过调用存储过程中的查询语句得到的,由于界面是分页显示的,一页100条数据,所以查询语句也是分页查的,导出第一页时查询主表的前100条,导出第二页时查询主表的第100到200条......从第二次查询开始,使用到了limit m,n语句。

这时候我们会注意到,每一次查询都会从主表的第一条数据开始查询,总共查询(page_size+1)*page_no条数据,随着page_no的增加,查询的无用数据也越来越多,导致了不必要的浪费。

基本这样的背景,我们可以创建临时表tmp_table,在第一次查询数据时保存主表rec_id到临时表里,这样从第二次开始,每次查询数据时使用

where tmp_table.rec_id > page_no*page_size limit page_size

可以避免数据库查询前page_no*page_size条数据,大大提高了查询效率,这种提高在导出数据越大的情况下提升的越明显,优化效率越高。

下面是创建临时表和第二页及以上的sql代码:

CREATE TEMPORARY TABLE `tmp_export_id`(
			rec_id INT NOT NULL AUTO_INCREMENT,
			goods_position_rec_id INT NOT NULL,
			PRIMARY KEY (`rec_id`)
		) ENGINE=MYISAM;
		
INSERT INTO tmp_export_id (goods_position_rec_id) 
SELECT 
  cgp.position_id 
FROM
  cfg_goods_position cgp 
  LEFT JOIN cfg_warehouse_position cwp 
    ON cgp.position_id = cwp.rec_id 
  LEFT JOIN goods_spec gs 
    ON cgp.spec_id = gs.spec_id 
  LEFT JOIN goods_goods gg 
    ON gs.goods_id = gg.goods_id 
  LEFT JOIN cfg_warehouse_zone cwz 
    ON cwz.zone_id = cgp.zone_id 
WHERE cwp.warehouse_id IN (1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19) 
  AND gs.owner_id IN (1, 3, 4, 5, 6, 7, 9, 10, 13, 14, 15, 16, 17) 
  AND cgp.type = 2  

创建并在临时表中插入信息,以便导出第二页及以后的信息时速度变快。

    SELECT 
    cgp.rec_id,
    gs.owner_id,
    gs.spec_no,
    gg.goods_no,
    gg.goods_name,
    gs.spec_code,
    gs.spec_name,
    cwp.warehouse_id,
    cwp.position_no,
    cwp.priority,
    cgp.type,
    cgp.zone_id,
    cwz.is_pop,
    cgp.created,
    cgp.modified 
  FROM
    tmp_export_id tei 
    INNER JOIN cfg_goods_position cgp 
      ON tei.goods_position_rec_id = cgp.rec_id 
    LEFT JOIN cfg_warehouse_position cwp 
      ON cgp.position_id = cwp.rec_id 
    LEFT JOIN goods_spec gs 
      ON cgp.spec_id = gs.spec_id 
    LEFT JOIN goods_goods gg 
      ON gs.goods_id = gg.goods_id 
    LEFT JOIN cfg_warehouse_zone cwz 
      ON cwz.zone_id = cgp.zone_id 
  WHERE tei.rec_id > 100 
    AND cwp.warehouse_id IN (1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19) 
    AND gs.owner_id IN (1, 3, 4, 5, 6, 7, 9, 10, 13, 14, 15, 16, 17) 
    AND cgp.type = 2 
  ORDER BY tei.rec_id ASC 
  LIMIT 100 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值