深度分页问题优化方案

问题原因

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

相关推荐

  • 界面设计器教程 -如何上传自定义组件

    自定义组件实战 【界面设计器】自定义字段组件实战——轮播图:https://doc.oinone.top/frontend/55.html 【界面设计器】自定义字段组件实战——表格字段组合展示https://doc.oinone.top/frontend/57.html 【界面设计器】自定义字段组件实战——表格字段内嵌表格https://doc.oinone.top/frontend/59.html 【界面设计器】自定义字段组件实战——千分位输入框https://doc.oinone.top/frontend/57.html

    2024年9月30日
    2.2K00
  • 3.5.6.4 动作的配置

    在3.5.3【Action的类型】一文中,我们介绍Action的几种类型,以及组合动作。 通用配置 配置项 可选值 默认值 作用 name 动作名称 label 显示名称 icon 图标 type primary defaultlink primary 按钮类型样式,支持主要样式、次要样式以及链接样式。 bizStyle defaultsuccesswarningdangerinfo default 按钮业务样式,支持成功(green)、警告(yellow)、危险(red)、信息(grey)四种样式。 invisible truefalse condition false 展示规则,有简单的true/false显隐,也支持复杂的表达式 disabled truefalse condition 根据动作上下文类型进行自动推断 是否禁用自动推断规则:当上下文类型为【单行】时,相当于使用表达式LIST_COUNT(context.activeRecords) != 1当上下文类型为【多行】时,相当于使用表达式LIST_COUNT(context.activeRecords) <= 1当上下文类型为【单行或多行】时,相当于使用表达式LIST_COUNT(context.activeRecords) == 0 disabledTitle string 根据动作上下文类型进行自动推断 禁用悬浮提示 表3-5-6-12 动作通用配置 二次确认配置 二次确认框默认支持两种模式,对话框和气泡框; 对话框 图3-5-6-51 对话框提示 气泡框 图3-5-6-52 气泡框警告 配置项 配置项 可选值 默认值 作用 备注 confirm string 二次确认提示文字 配置后开启二次确认 confirmType POPPER(气泡提示框) MODAL(对话框) POPPER 确认框类型 confirmPosition TM(按钮上方) BM(按钮下方) LM(按钮左侧) RM(按钮右侧) BM 确认框位置 气泡框该配置生效 enterText 确定 确定按钮文字 cancelText 取消 取消按钮文字 表3-5-6-13 配置项 弹出层动作配置(窗口动作ViewAction) 目前平台对于弹出层支持了两种展示形式。弹窗(modal/dialog)和抽屉(drawer) 支持两种配置方式【内嵌视图配置】和【引用已有页面】,内嵌视图配置优先于引用已有页面。 内嵌视图配置 该配置对于弹窗和抽屉均适用。 <action name="窗口动作名称" label="创建"> <view model="模型编码" type="form"> <template slot="form" widget="form"> <field data="id" invisible="true" /> <field data="code" label="编码" widget="Input" /> <field data="name" label="名称" widget="Input" /> </template> <template slot="footer"> <action name="$$internal_DialogCancel" label="关闭" type="default" /> <action name="create" label="确定" /> </template> </view> </action> 图3-5-6-53 内嵌视图配置 引用已有页面配置 该配置对于弹窗和抽屉均适用。 <view model="模型编码" type="form"> <template slot="form" widget="form"> <field data="id" invisible="true" /> <field data="code" label="编码" widget="Input" /> <field data="name" label="名称" widget="Input" /> </template> <template slot="footer"> <action name="$$internal_DialogCancel" label="关闭" type="default" /> <action name="create" label="确定" /> </template> </view> 图3-5-6-54 引用已有页面示例 <action name="窗口动作名称" label="创建" resViewName="$viewName$" /> 图3-5-6-55 引用已有页面 弹窗 当窗口动作的路由方式(target)为dialog时,内嵌视图/引用页面将以弹窗形式展示在页面上。 配置项 配置项 可选值 默认值 作用 title…

    2024年5月23日
    1.5K00
  • 正式版发布:Oinone 6.1.0 版本 新增AI设计器、虚拟字段,邀您体验

    版本号: 6.1.0 版本发布日期:2025.04.18更新要点:新增AI设计器、虚拟字段 6.1.0 版本 20250612升级内容 镜像版本升级: 6.1.4 –> 6.1.4.1 后端版本升级: 6.1.4 –> 6.1.4.1 修复Excel导出未正确翻译的问题 20250610升级内容 镜像版本升级: 6.1.3 –> 6.1.4 后端版本升级: 6.1.3 –> 6.1.4 修复模型导出数据序列异常的问题 修复工作流填写和审批节点无法正常修改触发节点多对一字段的问题 20250506升级内容 镜像版本升级: 6.1.2.4 –> 6.1.3 前端版本升级 后端版本升级: 6.1.2.4 –> 6.1.3 新增@XSchedule注解功能 新增Schedule定时任务支持cron表达式 修复跨模块继承在某些特殊情况下计算错误的问题 20250427升级内容 镜像版本升级: 6.1.2.3 –> 6.1.2.4 前端版本升级 后端版本升级: 6.1.2.3 –> 6.1.2.4 修复上游模块计算时显示名称、是否显示等属性未正确处理的问题 修复应用中心编辑时上游模块计算错误的问题 修复工作流使用整个流程结束后保存时无法正常保存的问题 开放应用支持自定义请求/响应处理函数 20250424升级内容 镜像版本升级: 6.1.1 –> 6.1.2.3 前端版本升级 后端版本升级: 6.1.1 –> 6.1.2.3 修复增强模型由于继承计算错误导致无法正常更新的问题 修复应用中心编辑时依赖模块计算错误的问题 修复打印设计器由于字体读取失败导致无法正常打印的问题 修复由于RequestAttribute处理错误导致无法正常同步导出和打印的问题 修复o2m、m2m字段表格默认排序字段没有回填 20250423升级内容 镜像版本升级: 6.1.0 –> 6.1.1 前端版本升级 后端版本升级: 6.1.0.4 –> 6.1.1 修复某些场景下无法正确移除数据的问题 内容类型切换可控制body参数类型是否清空 解决关系字段为枚举时查询条件枚举值问题 开放接口支持HL7-FHIR-JSON 集成接口支持熔断 升级内容(6.1.0) 新增AI设计器 新增虚拟字段 新增界面设计器多对一字段下钻添加子模型字段 自动生成的多对多中间模型所属模块默认使用字段定义模型所在模块(可能出现升级失败) 集成设计器支持HL7-FHIR-JSON协议 低代码模型无代码字段修改cloumn ddl 集成接口&开放接口调用监控统计 开放应用支持IP白名单、支持自定义响应状态码与响应结果 修复跨模块追加函数或模块重载时导致未启动模块元数据丢失的问题 修复登录页面语言与登录后不一致的问题 修复loading位置为屏幕高度一半 添加文件下载、拖拽上传、手写签名三个组件 修复微前端情况下多次初始化富文本编辑器菜单多次注册问题 上传api的回调函数非必填 低无一体生成的模版工程依赖简化 业务工程新增依赖项 <!– 元数据增强版本管理 –> <dependencyManagement> <dependencies> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-framework-meta-enchance</artifactId> <version>${pamirs.meta.enchance.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!– 虚拟字段 –> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-framework-meta-virtual</artifactId> </dependency> 请尽可能保证业务工程前后端服务以及设计器同步升级前端服务仅需重新执行npm run clean && npm install即可自动升级到最新版本 后端版本包信息 Oinone平台部署及依赖说明(v5.3) 未使用到的版本号请忽略,按项目中使用到的进行替换。 <!– 平台基础 –> <oinone.version>6.1.4.1</oinone.version> <!– 低无一体 –> <pamirs.paas.version>6.0.1</pamirs.paas.version> <!– 元数据增强 –> <pamirs.meta.enchance.version>6.0.1</pamirs.meta.enchance.version> <!– 设计器 –> <pamirs.workflow.designer.version>6.1.0</pamirs.workflow.designer.version> <pamirs.model.designer.version>6.1.2</pamirs.model.designer.version> <pamirs.ui.designer.version>6.1.2</pamirs.ui.designer.version> <pamirs.print.designer.version>6.1.1</pamirs.print.designer.version> <pamirs.data.designer.version>6.1.0</pamirs.data.designer.version> <pamirs.dataflow.designer.version>6.1.0</pamirs.dataflow.designer.version> <pamirs.eip.designer.version>6.1.2</pamirs.eip.designer.version> <pamirs.microflow.designer.version>6.1.0</pamirs.microflow.designer.version> <pamirs.ai.designer.version>6.1.0</pamirs.ai.designer.version> <dependencyManagement> <dependencies> <dependency> <groupId>pro.shushi</groupId> <artifactId>oinone-bom</artifactId> <version>${oinone.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs.paas</groupId> <artifactId>pamirs-paas-code-fuse-lite-core</artifactId> <version>${pamirs.paas.version}</version> </dependency> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-framework-meta-enchance</artifactId> <version>${pamirs.meta.enchance.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> oinone-bom详细版本信息 <!–…

    2025年4月21日
    1.3K00
  • 动态视图支持权限配置

    动态页面在前端自定义之后,目前是没办法通过权限去控制路由页面的权限的,本篇文章将介绍如何解决这个问题。阅读本篇文章之前,应已经实现自定义页面渲染动态视图。参考文章:自定义视图内部渲染动态视图 实现思路: 通过自定义页面里设计的组件api名字,获取配置的路由页面名字。 解析路由页面包含的所有动作,拼接权限节点。 将路由页面的权限节点,拼到自定义视图所在菜单的权限管理上。 效果,路由页面的动作出现在自定义视图所在的菜单权限节点上 代码示例 package pro.shushi.pamirs.top.core.auth; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.auth.api.entity.node.ActionPermissionNode; import pro.shushi.pamirs.auth.api.entity.node.PermissionNode; import pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi; import pro.shushi.pamirs.auth.api.loader.visitor.AuthCompileContext; import pro.shushi.pamirs.auth.api.loader.visitor.AuthCompileVisitor; import pro.shushi.pamirs.auth.api.loader.visitor.DslParser; import pro.shushi.pamirs.auth.api.pmodel.AuthResourceAuthorization; import pro.shushi.pamirs.auth.api.utils.AuthAuthorizationHelper; import pro.shushi.pamirs.boot.base.model.Menu; import pro.shushi.pamirs.boot.base.model.View; import pro.shushi.pamirs.boot.base.model.ViewAction; import pro.shushi.pamirs.boot.base.ux.model.UIView; import pro.shushi.pamirs.boot.base.ux.model.UIWidget; import pro.shushi.pamirs.boot.base.ux.model.view.UIField; import pro.shushi.pamirs.boot.web.loader.path.AccessResourceInfo; import pro.shushi.pamirs.boot.web.loader.path.ResourcePath; import pro.shushi.pamirs.boot.web.manager.MetaCacheManager; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.common.spi.SPI; import pro.shushi.pamirs.top.api.TopModule; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @Component @Order(88) @SPI.Service @Slf4j public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { @Autowired protected MetaCacheManager metaCacheManager; @Override public List<PermissionNode> buildNextPermissions(PermissionNode selected, List<PermissionNode> nodes) { // 动态页面所属的菜单name List<String> menuNames = new ArrayList<>(); menuNames.add("uiMenu3c094a75bd88461ba0ad780825069b32"); // 自定义组件api名称 List<String> apiNames = new ArrayList<>(); apiNames.add("dynamicView"); List<ActionPermissionNode> newNodes = new ArrayList<>(); for (String menuName : menuNames) { List<ActionPermissionNode> actionPermissionNodes = buildActionPermissionNodes(selected, menuName, apiNames); if (CollectionUtils.isNotEmpty(actionPermissionNodes)) { newNodes.addAll(actionPermissionNodes); } } nodes.addAll(newNodes); return nodes; } private List<ActionPermissionNode> buildActionPermissionNodes(PermissionNode selected, String menuName, List<String> apiNames) { String path = ResourcePath.generatorPath(TopModule.MODULE_MODULE, menuName); if (!path.equals(selected.getPath())) { return null; } Menu menu = metaCacheManager.fetchCloneMenus(TopModule.MODULE_MODULE).stream() .filter(v -> v.getName().equals(menuName)) .findFirst() .orElse(null); if (menu == null) { return null; } menu.fieldQuery(Menu::getViewAction); View mainView = fetchMainView(menu.getViewAction()); if (mainView == null) { return null; }…

    2025年9月10日
    1.4K00
  • 保存多值字段SQL执行报错

    定义多值类型时,字段类型应该设置为List类型。 @Field.String @Field(displayName ="经费证明", multi = true, serialize = Field.serialize.JSON) private List<String> matchFund; 场景复现

    2024年8月30日
    1.8K00

Leave a Reply

Please Login to Comment