当前位置: 首页 > news >正文

如何实现千万级数据表的快速分页查询

目录

  • 一、模拟数据
  • 二、正常分页查询
  • 三、优化方法
    • 1、利用主键的顺序性
    • 2、使用分页表

一、模拟数据

为了解决这个问题,我首先需要模拟生成三千万条数据,本来是想用Python生成的,但是最后发现生成效率太低了,最后我改用“随机生成+批量插入”的方案,来生成大量模拟数据。

具体实现思路如下:

DELIMITER //CREATE PROCEDURE GenerateRandomData(IN target_count INT, IN batch_size INT)
BEGINDECLARE current_count INT DEFAULT 0;DECLARE num_batches INT DEFAULT target_count DIV batch_size;DECLARE remainder INT DEFAULT target_count MOD batch_size;DECLARE i INT DEFAULT 0;-- 插入完整批次WHILE i < num_batches DOINSERT INTO orders (customer_id, order_date, origin, destination, status)SELECTFLOOR(RAND() * 1000000) + 1,CURDATE() - INTERVAL FLOOR(RAND() * 365 * 3) DAY,SUBSTRING(SHA(RAND()), 1, 10),SUBSTRING(SHA(RAND()), 1, 10),ELT(FLOOR(RAND() * 4) + 1, 'Pending', 'Shipped', 'Delivered', 'Cancelled')FROM(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t1,(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t2,(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t3,(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t4,(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t5;SET i = i + 1;END WHILE;-- 插入剩余的记录IF remainder > 0 THENINSERT INTO orders (customer_id, order_date, origin, destination, status)SELECTFLOOR(RAND() * 1000000) + 1,CURDATE() - INTERVAL FLOOR(RAND() * 365 * 3) DAY,SUBSTRING(SHA(RAND()), 1, 10),SUBSTRING(SHA(RAND()), 1, 10),ELT(FLOOR(RAND() * 4) + 1, 'Pending', 'Shipped', 'Delivered', 'Cancelled')FROM(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t1LIMIT remainder;  -- 使用LIMIT来插入剩余的记录数END IF;
END //DELIMITER ;

生成数据

CALL GenerateRandomData(32420006, 3125);

一共花了510秒,生成了三千多万条数据,相比于使用Python生成,效率还是挺高的。
在这里插入图片描述

SELECT COUNT(*) FROM orders

在这里插入图片描述

二、正常分页查询

如果直接使用正常的分页查询查询最后一页,总用时花费了22.7秒

SELECT * FROM orders
ORDER BY order_id
LIMIT 10 OFFSET 32402071;

在这里插入图片描述

为什么简单的分页查询会这么慢?

当我们使用 LIMITOFFSET 进行分页时,数据库需要扫描和跳过大量的行来找到偏移位置。在上面的代码中,数据库必须扫描超过 3240 万行才能返回 10 行。正是因为这个,导致我们的分页查询变得非常慢。

三、优化方法

要优化分页查询的速度,关键在于解决数据库为找到偏移位置而进行的大量扫描问题。 我们可以通过减少数据扫描量和优化数据访问路径来有效提升分页查询的性能。

1、利用主键的顺序性

通过利用主键的有序性来避免使用 OFFSET,可以有效提高查询效率。我们先按主键 id 排序,从表中跳过前面的记录,获取第 32402072 条记录的 id,并将其作为外层查询的基准起点。

SELECT order_id 
FROM orders 
ORDER BY order_id 
LIMIT 1 OFFSET 32402071

子查询返回第 32402072 条记录的 order_id,作为外层查询的起点。外层查询从这个 order_id 开始,选取所有大于或等于该 order_id 的记录,并按 order_id 升序排序。然后通过 LIMIT 10 限制结果,只返回从第 32402072 条记录开始的 10 条记录。

SELECT * 
FROM orders 
WHERE order_id >= (SELECT order_id FROM orders ORDER BY order_id LIMIT 1 OFFSET 32402071
)
ORDER BY order_id 
LIMIT 10;

在这里插入图片描述
如果MySQL版本是8.0以上,还可以这样写:

SELECT *
FROM orders
WHERE order_id IN (SELECT order_idFROM ordersORDER BY order_idLIMIT 10 OFFSET 32402071
);

2、使用分页表

创建一个临时表来存储分页查询的主键,然后再根据这些主键查询完整记录:

-- 创建一个临时表来存储分页的 order_id
CREATE TEMPORARY TABLE temp_order_ids AS
SELECT order_id
FROM orders
ORDER BY order_id
LIMIT 10 OFFSET 32402071;-- 使用临时表中的 order_id 来查询完整的记录
SELECT *
FROM orders
WHERE order_id IN (SELECT order_id FROM temp_order_ids);

在这里插入图片描述
如果是频繁使用分页查询,可以创建一个固定的表来存储分页的 id。

首先,创建一个固定表来存储分页的order_id

CREATE TABLE order_page_ids (order_id INT PRIMARY KEY
);

在进行分页查询之前,将所需的 order_id 插入到固定表中:

INSERT INTO order_page_ids (order_id)
SELECT order_id
FROM orders
ORDER BY order_id
LIMIT 10 OFFSET 32402071;

使用固定表中的 order_id 来获取完整的订单记录:

SELECT *
FROM orders
WHERE order_id IN (SELECT order_id FROM order_page_ids);

http://www.mrgr.cn/news/63760.html

相关文章:

  • github - ssh 配置 key、下载repo
  • 最经典的79个软件测试面试题(内含答案+文档)
  • 强大的文本编辑器Notepad++8.4.6 最新版
  • 基于hive分析Flask为后端框架echarts为前端框架的招聘网站可视化大屏项目
  • Docker本地安装Minio对象存储
  • Maven核心概念
  • 题目:0的个数
  • 冰雪奇缘!中科院一区算法+双向深度学习+注意力机制!SAO-BiTCN-BiGRU-Attention雪消融算法优化回归预测
  • systemctl restart NetworkManager 重启后,文件/etc/resolv.conf修改失败
  • Java XML一口气讲完!(p≧w≦q)
  • 利用frp进行SSH端口转发(内网穿透同理)
  • 【每日C/C++问题】
  • 【数据库系统概论】第3章 关系数据库标准语言SQL(一)数据查询(超详细)
  • __init__.py __all__和 __name__的作用及其用法
  • 《DelayQueue:Java界的“延时大师”》
  • Android 字节飞书面经
  • 生信入门第八课:RNA-seq比对、定量和差异分析
  • 项目_Linux_网络编程_私人云盘
  • Linux用户权限管理
  • Linux操作系统下载(centos)
  • 操作系统-多线程案例
  • 5天学习RAG路线图,你信吗?
  • 遥感图像Trento原始数据集下载
  • 如何在 Vue 页面中禁止选择、右键、复制及 F12 开发者工具
  • shell脚本编程
  • 奥数与C++小学四年级(第十八题 小球重量)