后端开发中为了防止一次性加载太多数据致使内存、磁盘IO都开销过大,常常须要分页展现,这个时候就须要用到MySQL的LIMIT关键字。但你觉得LIMIT分页就万事大吉了么,Too young,too simple啊,LIMIT在数据量大的时候很可能形成的一个问题就是深度分页。前端
这里我以显示电商订单详情为背景举个例子,新建表以下:面试
CREATE TABLE `cps_user_order_detail` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `user_id` varchar(32) NOT NULL DEFAULT '' COMMENT '用户ID', `order_id` bigint(20) DEFAULT NULL COMMENT '订单id', `sku_id` bigint(20) unsigned NOT NULL COMMENT '商品ID', `order_time` datetime DEFAULT NULL COMMENT '下单时间,格式yyyy-MM-dd HH:mm:ss', PRIMARY KEY (`id`), KEY `idx_time_user` (`order_time`,`user_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户订单详情';
而后手动向表里插入120W条数据。
如今有个需求:分页展现用户的订单详情,按照下单时间倒序。
表结构精简了,需求也简单。因而哗哗哗的写完代码,提测上线了。早期运行一切正常,可随着订单量的不断增大,发现系统愈加的缓慢,还时不时报出几个慢查询
。
这个时候你就该想到是LIMIT偏移的问题了,没错,不是你的SQL不够优美,就是MySQL自身的机制。
这里我就简单以两条SQL为例,以下图,分别是从100和100W的位置偏移分页,能够看到时间相差很大。这还不算其它数据运算和处理的时间,单一条SQL的查询就耗时一秒以上,在对用户提供的功能里这是不能容忍的(电商里常常要求一个接口的RT不超过200ms)。后端
这里咱们再看下执行计划,以下图所示:性能
在此先介绍一下执行计划Extra列可能出现的值及含义:
减小回表次数
的重大优化。再看看上图,一样的语句,只觉得偏移量不一样,就形成了执行计划的千差万别(且容我小小的夸张一下)。第一条语句LIMIT 100,6
type列的值是range
,表示范围扫描,性能比ref
差一个级别,可是也算走了索引,而且还应用了索引下推:就是说在WHERE以后的下单时间删选走了索引,而且以后的ORDER BY也是根据索引下推优化,在执行WHERE条件筛选时同步进行的(没有回表)。
而第二条语句LIMIT 1000000,6
压根就没走索引,type列的值是ALL
,显然是全表扫描。而且Extra列字段里的Using where表示发生了回表,Using filesort表示ORDER BY时发生了文件排序。因此这里慢在了两点:一是文件排序耗时过大,二是根据条件筛选了相关的数据以后,须要根据偏移量回表获取所有值。不管是上面的哪一点,都是LIMIT偏移量过大致使的,因此实际开发环境常常遇到非统计表量级不得超过一百万的要求。优化
缘由分析完了,那么LIMIT深度分页在实际开发中怎么优化呢?这里少侠给两点方案。
一是经过主键索引优化。什么意思呢?就是把上面的语句修改为:搜索引擎
SELECT * FROM cps_user_order_detail d WHERE d.id > #{maxId} AND d.order_time>'2020-8-5 00:00:00' ORDER BY d.order_time LIMIT 6;
如上代码所示,一样也是分页,可是有个maxId的限制条件,这个是什么意思呢,maxId就是上一页中的最大主键Id。因此采用此方式的前提:1)主键必须自增不能是UUID而且前端除了传基本分页参数pageNo,pageSize外,还必须把每次上一页的最大Id带过来,2)该方式不支持随机跳页,也就是说只能上下翻页。以下图所示是某知名电商中的实际页面。spa
二是经过Elastic Search搜索引擎(基于倒排索引),实际上相似于淘宝这样的电商基本上都是把全部商品放进ES搜索引擎里的(那么海量的数据,放进MySQL是不可能的,放进Redis也不现实)。但即便用了ES搜索引擎,也仍是有可能发生深度分页的问题的,这时怎么办呢?答案是经过游标scroll。关于此点这里不作深刻,感兴趣的能够作研究。3d
写这篇博客是由于前段时间在开发中真实经历到了,而且以前在字节面试中确实也和面试官探讨了一番。知道LIMIT的限制以及优化,在面试中能提到是加分项,不能说到MySQL优化就是建索引,调整SQL(实际上在真实开发中这两种优化方案的成效微乎其微)。毕竟MySQL优化那么牛X的话,就不会有那么多中间件产生了。
我是少侠露飞,爱技术,爱分享。code