深度分页问题优化方案

问题原因

Mysql使用select * from table limit offset, rows分页在深度分页的情况下, 性能急剧下降。

例如:select * 的情况下直接⽤limit 600000,10 扫描的是约60万条数据,并且是需要回表 60W次,也就是说⼤部分性能都耗在随机访问上,到头来只⽤到10条数据(总共取600010条数据只留10条记录)

优化方案

前端方案:业务层面限制跨度比较大的跳页

提供2种风格分页器供用户选择

  1. 标准分页器,展示最后一页和跳转指定页输入框
    image.png
  2. 简单分页器
    image.png

参考
百度方案: 不展示最后一页和直接跳转指定分页的输入框
image.png
Google方案:只展示查看下一页的按钮
image.png

界面设计器选表格/画廊的属性面板提供分页器风格的属性下拉选择

image.png

xml示例
<!-- 表格使用的标准分页器 --> <view type="TABLE" paginationStyle="SIMPLE"> <!-- fields --> </view> <!-- 画廊使用默认的标准分页器 --> <view type="GALLERY" paginationStyle="STANDARD"> <!-- fields --> </view>

后端方案

  1. 使用索引:确保数据库表中的相关字段上创建了适当的索引。索引可以加快查询速度,特别是在处理大数据量时。

  2. 分批查询:将大数据分成多个较小的批次进行查询,而不是一次性查询全部数据。可以通过限制每次查询的数据量和使用合适的偏移量来实现分批查询,例如使用LIMIT和OFFSET子句。

  3. 基于游标的分页:使用基于游标的分页技术,而不是传统的偏移分页。游标分页是通过记录上一次查询的游标位置,在下一次查询时从该位置开始获取新的数据,避免了大偏移量的影响。这可以通过数据库自身的功能(例如MySQL的CURSOR)或使用第三方库来实现。

  4. 缓存数据:如果数据变化较少,可以考虑将查询结果缓存到内存中,以避免频繁地查询数据库。这样可以提高页面相应速度,并减轻数据库负担。缓存的数据应该根据业务需要及时更新。

  5. 数据预处理:如果查询结果经常需要进行复杂的计算或处理,可以考虑提前对数据进行预处理并缓存结果,以减少每次查询的计算负担。

  6. 数据库优化:针对具体数据库系统,可以根据实际情况进行数据库调优。例如,合理设置数据库连接池大小、调整数据库参数等。

  7. 分布式存储和计算:对于非关系型数据库或分布式存储系统,可以考虑使用分布式存储和计算方案,将数据分散存储在多个节点上,并通过计算节点并行处理查询请求,以提高性能和可伸缩性。

参考链接

MySQL深分页场景下的性能优化

Oinone社区 作者:原创文章,如若转载,请注明出处:https://doc.oinone.top/other/75.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
's avatar
Previous 2023年6月20日 pm4:07
Next 2023年11月2日 pm1:58

相关推荐

  • 4.1.10 函数之触发与定时(改)

    函数的触发和定时在很多场景中会用到,也是一个oinone的基础能力。比如我们的流程产品中在定义流程触发时就会让用户选择模型触发还是时间触发,就是用到了函数的触发与定时能力。 整体链路示意图(如下图4-1-10-1 所示),本文只讲trigger里的两类任务,一个是触发任务,一个是定时任务,异步任务放在4.1.11【函数之异步执行】一文中单独去介绍。 图4-1-10-1 整体链路示意图 一、触发任务TriggerTaskAction(举例) 触发任务的创建,使用pamirs-middleware-canal监听mysql的binlog事件,通过rocketmq发送变更数据消息,收到MQ消息后,创建TriggerAutoTask。 触发任务的执行,使用TBSchedule拉取触发任务后,执行相应函数。 注意:pamirs-middleware-canal监听的数据库表必须包含触发模型的数据库表。 Step1 下载canal中间件 下载pamirs-middleware-canal-deployer-3.0.1.zip,去.txt后缀为pamirs-middleware-canal-deployer-3.0.1.zip,解压文件如下: 图4-1-10-2 下载canal中间件 Step2 引入依赖pamirs-core-trigger模块 pamirs-demo-api增加pamirs-trigger-api <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-api</artifactId> </dependency> 图4-1-10-3 pamirs-trigger-api依赖包 DemoModule在模块依赖定义中增加@Module(dependencies={TriggerModule.MODULE_MODULE}) @Component @Module( name = DemoModule.MODULE_NAME, displayName = "oinoneDemo工程", version = "1.0.0", dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE, UserModule.MODULE_MODULE, TriggerModule.MODULE_MODULE} ) @Module.module(DemoModule.MODULE_MODULE) @Module.Advanced(selfBuilt = true, application = true) @UxHomepage(PetShopProxy.MODEL_MODEL) public class DemoModule implements PamirsModule { ……其他代码 } 图4-1-10-4 模块依赖中增加Trigger模块 pamirs-demo-boot 增加pamirs-trigger-core和pamirs-trigger-bridge-tbschedule的依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-bridge-tbschedule</artifactId> </dependency> 图4-1-10-5 增加pamirs-trigger-core和pamirs-trigger-bridge-tbschedule的依赖 修改pamirs-demo-boot的applcation-dev.yml 修改pamris.event.enabled和pamris.event.schedule.enabled为true pamirs_boot_modules增加启动模块:trigger pamirs: event: enabled: true schedule: enabled: true rocket-mq: namesrv-addr: 127.0.0.1:9876 boot: init: true sync: true modules: – base – common – sequence – resource – user – auth – message – international – business – trigger – demo_core 图4-1-10-6 启动模块中增加trigger模块 Step3 启动canal中间件 canal的库表需要手工建 create schema canal_tsdb collate utf8mb4_bin 图4-1-10-7 canal的建库语句 CREATE TABLE IF NOT EXISTS `meta_snapshot` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `gmt_create` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '修改时间', `destination` varchar(128) DEFAULT NULL COMMENT '通道名称', `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名', `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量', `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id', `binlog_timestamp` bigint(20) DEFAULT NULL…

    2024年5月23日
    1.9K00
  • 新增模块不存在

    后端代码新增了一个模块,但在前端看不到新增的模块,主要排查以下几个方面 检查启动参数中是否添加-Plifecycle=INSTALL。 启动工程的yml文件中在pamirs: boot: modules: 中是否添加了该模块 启动工程的pom文件是否依赖该该模块所在包 检查启动工程是否扫描到了该模块所在包

    2024年7月23日
    2.2K00
  • 前端 SPI 注册 + 渲染

    在阅读本篇文章之前,您需要学习以下知识点: 1: TS 结合 Vue 实现动态注册和响应式管理 前端开发者在使用 oinone 平台的时候会发现,不管是自定义字段还是视图,对应的 typescript 都会用到@SPI.ClassFactory(参数),然后在对用的class中重写initialize方法`: @SPI.ClassFactory(参数) export class CustomClass extends xxx { public initialize(props) { super.initialize(props); this.setComponent(FormString); return this; } } 本文将带您熟悉 oinone 前端的 SPI 注册机制以及 TS + Vue 的渲染过程。 不管是自定义字段还是视图@SPI.ClassFactory(参数)都是固定写法,区别在于参数不同,这篇文章里面详细描述了参数的定义。 SPI 注册机制 有自定义过字段、视图经验的开发者可能会发现,字段(表单字段)SPI 注册用的是FormFieldWidget.Token生成对应的参数,视图 SPI 注册用的是BaseElementWidget.Token,那么为什么要这样定义呢? 大家可以想象成现在有一个大的房子,房子里面有很多房间,每个房间都有自己的名字,比如FormFieldWidget就是房间的名字,BaseElementWidget也是房间的名字,这样一来我们就可以根据不同的房间存放不同的东西。 下面给大家展示下伪代码实现: class SPI { static container = new Map<string, WeakMap<object, object>>() static ClassFactory(token) { return (target) => { if(!SPI.container.get(token.type)) { SPI.container.set(token.type, new WeakMap()) } const services = SPI.container.get(token.type) services?.set(token, target) } } } class FormFieldWidget { static Token(options) { return { …options, type: 'Field' } } static Selector(options) { const fieldWidgets = SPI.container.get('Field') if(fieldWidgets) { return fieldWidgets.get(options)! } return null } } @SPI.ClassFactory(FormFieldWidget.Token({ viewType: 'Form', ttype: 'String', widget: 'Input' })) class StringWidget { } // 字段元数据 const fieldMeta = { name: "name", field: "name", mode: 'demo.model', widget: 'Input', ttype: 'String', viewType: 'Form' } // 找到对应的widget const widget = FormFieldWidget.Selector({ viewType: fieldMeta.viewType, ttype: fieldMeta.ttype, widget: fieldMeta.widget, }) 在上述代码中,我们主要是做了这么写事情: 1.SPI class class SPI { static container = new Map<string, WeakMap<object, object>>() } SPI 类是一个静态类,用于管理服务的注册和获取。 container 是一个静态属性,类型是 Map,它的键是字符串,值是 WeakMap。这个结构允许我们为每个服务类型(例如,Field)管理多个服务实例。 2.ClassFactory 方法 static ClassFactory(token) { return (target) => { if…

    2024年9月26日
    2.3K00
  • 早鸟版发布:Oinone 7.0.0 版本 升级 JDK17,优化全平台界面交互,邀您体验

    版本号: 7.0.0 版本发布日期:2025.12更新要点:升级 JDK17,优化全平台界面交互 7.0.0 版本 GitHub: 后端: https://github.com/oinone/oinone-pamirs 前端: https://github.com/oinone/oinone-kunlun Gitee: 后端: https://gitee.com/oinone/oinone-pamirs 前端: https://gitee.com/oinone/oinone-kunlun 升级说明及步骤 此版本升级时需要完整回归已有系统的已有功能,否则无法保证功能的正常使用。尤其是 javax -> jakarta 的变更会出现编译正常但无法正常运行的情况。 7.0.0升级详细说明及步骤 20260721 升级内容 镜像版本升级: 7.0.7 –> 7.0.8 后端版本升级: 7.0.7 –> 7.0.8 修复工作流发布时视图重复生成的问题 20260720 升级内容 镜像版本升级: 7.0.6 –> 7.0.7 后端版本升级: 7.0.6 –> 7.0.7 修复工作流回退节点导出的问题 修复低代码模型导入无代码字段时元数据差量计算错误的问题 20260608 升级内容 镜像版本升级: 7.0.5 –> 7.0.6 后端版本升级: 7.0.5.1 –> 7.0.6 修复工作流元数据导入找不到自定义函数的问题 修复工作流元数据导入导致流程重复触发的问题 20260129 升级内容 镜像版本升级: 7.0.4 –> 7.0.5 后端版本升级: 7.0.4 –> 7.0.5.1 前端版本升级 修复新模型的表格首次设置冻结渲染错误的问题 修复流程设计器数据权限表单字段丢失问题 修复业务流程抽屉转换为弹窗时高度异常的问题 20260117 升级内容 镜像版本升级: 7.0.3.1 –> 7.0.4 后端版本升级: 7.0.3 –> 7.0.4 前端版本升级 修复语言保存时毫秒格式验证错误的问题 修复界面设计器多对一表单配置提交函数过滤错误的问题 修复元数据导入时菜单无法更新动作的问题 修复工作流集成接口在某些情况下参数处理错误的问题 20260109 升级内容 升级此版本需要开启元数据全量刷新 pamirs.distribution.session.allMetaRefresh=true 镜像版本升级: 7.0.2 –> 7.0.3.1 后端版本升级: 7.0.2 –> 7.0.3 前端版本升级 修复工作流数据安装 增加对函数操作日志 增加函数操作规则设置 用户登录日志增加扩展点 时间格式支持毫秒 Eip日志增加毫秒支持 优化导出API 的文档结构 点击查看用户手册 集成接口日志参数信息支持 JSON/XML 格式切换及一键复制 点击查看用户手册 数据库 API 支持格式化 / 压缩SQL格式 点击查看用户手册 数据流程增加毫秒支持 语言增加毫秒支持 集成接口和开发接口日志统计增加日期范围筛选 增加标准心跳检查 trigger增加扩展点,适配多租户场景 增加导入文件URL错误,获取不到JSON的日志 解决元数据增强可能出现的死循环 修复集成设计器弹窗宽度问题 修复表格配置双击行动作,未预留动作区高度的问题 修复自定义 mask 变更 actionBar 插槽名称导致无法正常渲染的问题 20251229 升级内容 镜像版本升级: 7.0.1 –> 7.0.2 后端版本升级: 7.0.1 –> 7.0.2 前端版本升级 修复工作流元数据安装异常的问题 前端包名变更:@kunlun/vue-grid-layout@2.3.13 –> @oinone/vue-grid-layout@2.3.13 前端包名变更:webpack-aliyun-oss@0.5.2 –> @oinone/webpack-aliyun-oss@0.5.2 npmrc 统一配置 registry=https://registry.npmmirror.com/ @oinone:registry=http://nexus.shushi.pro/repository/kunlun/ legacy-peer-deps=true 20251220 升级内容 镜像版本升级: 7.0.0 –> 7.0.1 前端版本升级 界面设计器上传图片组件新增cdnKey配置 修复系统权限字段丢失导致无法正常运行的问题 修复全屏按钮悬浮文案 修复快捷键提示文案 修复取消排序展示错误的问题 修复快速填报选择不粘贴时数据处理错误的问题 修复流程设计器无法编辑流程名称的问题 修复移动端打包失败的问题 修复体验镜像RocketMQ无法正常启动的问题 20251217 升级内容 镜像版本升级: 7.0.0 后端版本升级: 7.0.1 前端版本升级 升级…

    2025年12月17日
    1.5K00
  • 左树右表,支撑不同场景的树表结构

    左树右表俩种情况 假设存在 A模型 B模型 1: 左树为A模型,右表为B模型 举例 A模型为类目 B模型为类目属性模型代码实例: @Model.model(AriesPlatformCategory.MODEL_MODEL) @Model(displayName = "平台后台类目", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategory extends AriesCategory { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategory"; @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; } @Model.model(AriesPlatformCategoryAttr.MODEL_MODEL) @Model(displayName = "Aries_平台类目属性", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategoryAttr extends CategoryAttr { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategoryAttr"; @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; } 在设计器设计左树右表之前,需要在模型 中配置好关联关系 。如下部分代码 配置好类目与父类目的关联关系。 @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; 配置好 类目与类目属性的关联关系。一个类目可以有多个类目属性,一对多one2many @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; 在类目属性模型中,配置好属性与类目的关联关系,一个类目属性只属于一个类目,一个类目可以有多个类目属性。类目属性对类目多对一many2one @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; 设计器实例:1.需要选择 平台类目属性 做为主模型创建树表页面2.构建关联关系 选择平台后台类目 第一级的筛选条件 上级编码为空 表格关联关系字段 选择 平台类目属性。 3.表格拖拽好需要的属性字段 2: 左树为A模型,右表也为A模型 举例 左A模型 组织结构管理 右A模型 组织结构管理模型代码实例: @Model.model(BasicOrg.MODEL_MODEL) @Model(displayName = "组织结构管理", summary…

    2024年2月20日
    4.2K00

Leave a Reply

Please Login to Comment