MySQL 分页 Limit性能测试
版本:5.6.30
一般的分页查询使用简单的 limit 子句就可以实现。limit 子句声明如下:
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset |
SELECT * FROM resource ORDER BY id DESC LIMIT 50000,10;
该条语句将会从表 resource 中查询offset: 50001开始之后的10条数据,也就是第1条到第50010条数据。(50001<= id <= 50010)
MySQL的查询并非先跳过50000条,再查询10条,而是先查询再跳过。所以上面例子,要先查询出50010行之后,再取10条,速度当然很慢,并且跳过的行数越多,会越慢。
就比如看一本500页的书,上次看到480页,下次再看从第一页翻到480,然后再接着上次的继续看。 MySQL在执行上面这个SQL的时候大部分时间用在了翻书这个动作上。
数据准备:
resource_b表数据1000万条数据
CREATE TABLE `resource_b` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `resource_code` varchar(64) DEFAULT NULL COMMENT '资源编号', `original_resource_amount` decimal(14,2) DEFAULT NULL COMMENT '原始金额', `resource_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `ab_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `ab_net_amount` decimal(14,2) DEFAULT NULL COMMENT '净额', `shangbiao_fee_amount` decimal(14,2) DEFAULT NULL COMMENT '化妆资源品牌费金额', `shangbiao_fee_ratio` decimal(14,4) DEFAULT NULL COMMENT '资源品牌方点位', `pps_amount` decimal(14,2) DEFAULT NULL COMMENT '信息服务费', `resource_chl_id` varchar(64) DEFAULT NULL COMMENT 'Test资源商户', `auth_user_mobile` varchar(32) DEFAULT NULL, `city_code` varchar(64) DEFAULT NULL COMMENT '城市', `product_id` varchar(64) DEFAULT NULL COMMENT '产品实例ID', `fund_id` varchar(64) DEFAULT NULL COMMENT '资金方ID', `applicant_uid` varchar(64) DEFAULT NULL COMMENT '资源人' PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4 COMMENT='资源单' |
resource 50万条数据
CREATE TABLE `resource` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `resource_code` varchar(64) DEFAULT NULL COMMENT '资源编号', `original_resource_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `resource_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `ab_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `ab_net_amount` decimal(14,2) DEFAULT NULL COMMENT '净额', `shangbiao_fee_amount` decimal(14,2) DEFAULT NULL COMMENT '资源品牌费金额', `shangbiao_fee_ratio` decimal(16,6) DEFAULT NULL COMMENT '代付资源品牌方点位', `pps_amount` decimal(14,2) DEFAULT NULL COMMENT ' 服务费', `auth_user_mobile` varchar(20) DEFAULT NULL, `resource_chl_id` varchar(64) DEFAULT NULL COMMENT '资源商户', `city_code` varchar(64) DEFAULT NULL COMMENT '城市', `product_id` varchar(64) DEFAULT NULL COMMENT '产品实例ID', `fund_id` varchar(64) DEFAULT NULL COMMENT '资金方', `applicant_uid` varchar(64) DEFAULT NULL COMMENT '资源人', `fee_rate` decimal(10,4) DEFAULT NULL COMMENT '费率', `resource_ratio` decimal(14,4) DEFAULT NULL COMMENT '折扣', `status` int(4) DEFAULT NULL COMMENT ' ', `resource_time` datetime DEFAULT NULL COMMENT '资源时间' PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='资源单' |
resource_a 100万条数据
CREATE TABLE `resource_a` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `resource_code` varchar(64) DEFAULT NULL COMMENT '资源编号', `original_resource_amount` decimal(14,2) DEFAULT NULL COMMENT '原始金额', `resource_amount` decimal(14,2) DEFAULT NULL COMMENT '金额', `ab_amount` decimal(14,2) DEFAULT NULL COMMENT '应收金额', `ab_net_amount` decimal(14,2) DEFAULT NULL COMMENT '实际金额', `shangbiao_fee_amount` decimal(14,2) DEFAULT NULL COMMENT '资源品牌费金额', `shangbiao_fee_ratio` decimal(14,4) DEFAULT NULL COMMENT '资源品牌方点位', `pps_amount` decimal(14,2) DEFAULT NULL COMMENT '服务费', `resource_chl_id` varchar(64) DEFAULT NULL COMMENT '资源商户', `auth_user_mobile` varchar(32) DEFAULT NULL, `city_code` varchar(64) DEFAULT NULL COMMENT '城市', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='资源单' |
性能测试
50万条数据测试
查询数据量的测试:
-- 0.125 secSELECT * FROM resource ORDER BY id DESC LIMIT 50000,1;-- 0.126 secSELECT * FROM resource ORDER BY id DESC LIMIT 50000,10;-- 0.126 secSELECT * FROM resource ORDER BY id DESC LIMIT 50000,100; -- 0.126 secSELECT * FROM resource ORDER BY id DESC LIMIT 50000,1000; |
查询偏移量的测试:
-- 0.001 secSELECT * FROM resource ORDER BY id DESC LIMIT 100,1;-- 0.003 secSELECT * FROM resource ORDER BY id DESC LIMIT 1000,10;-- 0.026 secSELECT * FROM resource ORDER BY id DESC LIMIT 10000,10;-- 1.681 secSELECT * FROM resource ORDER BY id DESC LIMIT 490000,10; |
100万条数据测试
-- 0.001 secSELECT * FROM resource_a ORDER BY id DESC LIMIT 1000,10;-- 0.009 secSELECT * FROM resource_a ORDER BY id DESC LIMIT 10000,10;-- 0.085 secSELECT * FROM resource_a ORDER BY id DESC LIMIT 90000,10; -- 0.905 secSELECT * FROM resource_a ORDER BY id DESC LIMIT 990000,10; |
1000万条数据测试
-- 翻书 7.874334-- 总耗时:13.842secSELECT * FROM resource_b ORDER BY id DESC LIMIT 9000000,10; |
Sending data(收集+发送数据)
优化方案
方案A:(《高性能MySQL》书中提到的)
--1000万条数据-- 翻书 2.134621 -- 总耗时 3.753secSELECT *FROM resource_b a INNER JOIN (SELECT id FROM resource_b LIMIT 9000000, 10) AS b ON a.id = b.id; |
方案B:( id 递增的情况,中间的记录没有被物理删除过 )
SELECT * FROM resource_b WHERE id > 9000000 ORDER BY id DESC LIMIT 10; |
优化方案性能对比
方法一:
--1000万条数据-- 翻书 2.134621 -- 总耗时 3.753secSELECT *FROM resource_b a INNER JOIN (SELECT id FROM resource_b LIMIT 9000000, 10) AS b ON a.id = b.id; |
-- 100万条数据-- 翻书 0.156227-- 总耗时 0.271sec SELECT *FROM resource_a a INNER JOIN (SELECT id FROM resource_a LIMIT 900000 , 10) AS b ON a.id = b.id; |
-- 50万条数据-- 翻书 0.310197-- 总耗时 0.558sec SELECT *FROM resource a INNER JOIN (SELECT id FROM resource LIMIT 490000 , 10) AS b ON a.id = b.id; |
方法二:
-- 1000万条数据 -- 翻书 0.000049 -- 总耗时0.0015sec-- rang indexSELECT * FROM resource_b WHERE id > 9000000 ORDER BY id DESC LIMIT 10; |
-- 100万条数据-- 翻书 0.000039-- 总耗时0.001secSELECT * FROM resource_a WHERE id > 900000 ORDER BY id DESC LIMIT 10; |
-- 50万条数据 -- 翻书 0.000103 -- 总耗时0.001secSELECT * FROM resource WHERE id > 490000 ORDER BY id DESC LIMIT 10; |
总结:
在查询数据量limit a,b时b的大小没有太大影响,最终的影响点在a的大小上面。
50万数据resource表里LIMIT 490000,10 需要消耗1.68秒时间
100万数据resource_b表里LIMIT 990000,10耗时0.905秒(表结构不一样)
1000万数据resource_a表里LIMIT 9000000,10总耗时:13.842秒(大概需要14秒时间)
优化方案A通过 join方式查询,1千万条数据 LIMIT 9000000,10总耗时 3.753sec性能提升了3倍
优化方案A通过id>9000000方式查询,1千万条数据总耗时0.0015sec

浙公网安备 33010602011771号