深度分页问题优化方案

问题原因

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.7.8.4版本升级说明-20240418

    版本号: 4.7.8.4版本发布日期:2024.04.18更新要点:界面设计器关系字段新增穿梭框、单选框、复选框组件 4.7.8.4版本 升级内容 一对多和多对多关系字段新增穿梭框组件 一对多和多对多关系字段新增复选框组件 多对一关系字段新增单选框组件 版本包信息 未使用到的版本号请忽略,按项目中使用到的进行替换 <!–平台基础jar包–> <pamirs.middleware.version>4.7.8.3</pamirs.middleware.version> <pamirs.k2.version>4.7.8.3</pamirs.k2.version> <pamirs.boot.version>4.7.8.4</pamirs.boot.version> <pamirs.framework.version>4.7.8.4</pamirs.framework.version> <pamirs.core.version>4.7.8.4</pamirs.core.version> <pamirs.distribution.version>4.7.8.3</pamirs.distribution.version> <pamirs.metadata.manager>4.7.8</pamirs.metadata.manager> <pamirs.lowcode.version>4.7.8</pamirs.lowcode.version> <!–设计器jar包–> <pamirs.designer.common.version>4.7.8</pamirs.designer.common.version> <pamirs.workflow.version>4.7.8</pamirs.workflow.version> <pamirs.flow.designer.base.version>4.7.8</pamirs.flow.designer.base.version> <pamirs.dataflow.designer.version>4.7.8</pamirs.dataflow.designer.version> <pamirs.workflow.designer.version>4.7.8</pamirs.workflow.designer.version> <pamirs.workbench.version>4.7.8</pamirs.workbench.version> <pamirs.model.designer.version>4.7.8</pamirs.model.designer.version> <pamirs.ui.designer.version>4.7.8.3</pamirs.ui.designer.version> <pamirs.data.designer.version>4.7.8</pamirs.data.designer.version> <pamirs.data.visualization.version>4.7.8</pamirs.data.visualization.version> <pamirs.eip.designer.version>4.7.8</pamirs.eip.designer.version> docker pull harbor.oinone.top/oinone/designer:4.8.1.3-allinone-fulldocker pull harbor.oinone.top/oinone/designer:4.8.1.3-allinone-mini 如果您有任何问题、建议或反馈,请随时联系我们。为了获得最佳体验,请及时更新至最新版本。我们将继续努力改进产品,提供更好的服务。谢谢!

    2024年4月18日
    1.5K00
  • 3.5.7.5 自定义动作

    动作是什么 动作(action)描述了终端用户的各种操作。这些操作可以涉及多个层面,包括但不限于: 页面间的跳转:用户可以通过动作从一个页面跳转到另一个页面。 业务交互:动作可以触发与后端服务的交互,例如提交表单、请求数据等。 界面操作:动作可以用于打开模态对话框、抽屉(侧边栏)等界面元素。 作用场景 Oinone 平台内置了一系列的基础动作,默认实现了常见的功能,如页面跳转、业务交互和界面操作等。这些内置动作旨在满足大多数标准应用场景的需求,简化开发过程,提高开发效率。以下是一些常见的内置动作示例: 页面跳转:允许用户在不同页面间导航。 业务交互:支持与后端服务的数据交互,如提交表单。 界面操作:提供动态返回上一页、校验表单、关闭弹窗等。 自定义动作的需求场景 尽管内置动作覆盖了许多常规需求,但在某些复杂或特定的业务场景中,可能需要更加个性化的处理。这些场景可能包括: 特殊的业务逻辑:需要执行不同于标准流程的特定业务操作。 个性化的用户界面:标准的 UI 组件无法满足特定的设计要求。 高级交互功能:需要实现复杂的用户交互和数据处理。 扩展和定制动作 为了满足这些特定需求,Oinone 平台支持通过继承和扩展来自定义动作。开发者可以通过以下步骤实现自定义动作: 继承基类:从平台提供的动作基类继承,这为自定义动作提供了基础框架和必要的接口。 实现业务逻辑:在继承的基础上,添加特定的业务逻辑实现。 自定义界面:根据需要调整或完全重写界面组件,以符合特定的UI设计。 集成测试:确保自定义动作在各种情况下的稳定性和性能。 最佳实践 明确需求:在进行扩展之前,清楚地定义业务需求和目标。 重用现有功能:尽可能利用平台的内置功能和组件。 保持一致性:确保自定义动作与平台的整体风格和标准保持一致。 充分测试:进行全面的测试,确保新动作的稳定性和可靠性。 案例分析 假设有一个场景,需要一个特殊的数据提交流程,该流程不仅包括标准的表单提交,还涉及复杂的数据验证和后续处理。在这种情况下,可以创建一个自定义动作,继承基础动作类并实现特定的业务逻辑和用户界面。 自定义动作 自定义跳转动作 示例工程目录 以下是需关注的工程目录示例,main.ts更新导入./action,action/index.ts更新导出./custom-viewactioin: 图3-5-7-24 自定义跳转动作工程目录示例 步骤 1: 创建自定义动作类 首先,您创建了一个名为 CustomViewAction 的类,这个类继承自 RouterViewActionWidget。这意味着自定义动作是基于路由视图动作的,这通常涉及页面跳转或导航。 import {ActionWidget, RouterViewActionWidget, SPI} from '@kunlun/dependencies'; import CustomViewActionVue from './CustomViewAction.vue'; @SPI.ClassFactory( ActionWidget.Token({ model: 'resource.ResourceCity', name: 'redirectCreatePage' }) ) export class CustomViewAction extends RouterViewActionWidget { public initialize(props) { super.initialize(props); this.setComponent(CustomViewActionVue); return this; } } 图3-5-7-24 自定义跳转动作组件(TS)代码示例 @SPI.ClassFactory: 这是一个装饰器,用于向平台注册这个新的动作。 ActionWidget.Token: 通过这个Token,指定了这个动作与特定模型 (resource.ResourceCity) 关联,并给这个动作命名 (redirectCreatePage). 步骤 2: 初始化和设置组件 在 initialize 方法中,调用了父类的初始化方法,并设置了自定义的 Vue 组件。 public initialize(props) { super.initialize(props); this.setComponent(CustomViewActionVue); return this; } 图3-5-7-24 初始化和设置组件 步骤 3: 定义 Vue 组件 在 CustomViewAction.vue 文件中,定义了自定义动作的视觉表示。 <template> <div class="view-action-wrapper"> 自定义挑战跳转动作 </div> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ inheritAttrs: false, name: 'ViewActionComponent' }) </script> <style lang="scss"> .view-action-wrapper { } </style> 图3-5-7-24 自定义跳转动作组件(Vue)代码示例 步骤 4: 效果如下 图3-5-7-24 自定义跳转动作效果示例 自定义服务器动作 示例工程目录 以下是需关注的工程目录示例,action/index.ts更新导出./custom-serveraction: 图3-5-7-24 自定义服务器动作工程目录示例 步骤 1: 创建自定义动作类 首先, 创建了一个名为 CustomServerAction 的类,这个类继承自 ServerActionWidget。这表明您的自定义动作主要关注服务器端的逻辑。 import {ActionWidget, ServerActionWidget, SPI, Widget} from '@kunlun/dependencies'; import CustomServerActionVue from './CustomServerAction.vue'; @SPI.ClassFactory( ActionWidget.Token({ model: 'resource.ResourceCity', name: 'delete' })…

    2024年5月23日
    1.6K00
  • 4.7.8.31 版本升级说明-20241220

    版本号: 4.7.8.31 版本发布日期:2024.12.20更新要点:表达式变量控件中单个字符串最大输入长度为500 4.7.8.31 版本 升级内容 表达式变量控件中单个字符串最大输入长度为500 版本包信息 Oinone平台部署及依赖说明(v4.7) 未使用到的版本号请忽略,按项目中使用到的进行替换 <!– 平台基础 –> <pamirs.middleware.version>4.7.8.5</pamirs.middleware.version> <pamirs.k2.version>4.7.8.8</pamirs.k2.version> <pamirs.framework.version>4.7.8.21</pamirs.framework.version> <pamirs.boot.version>4.7.8.14</pamirs.boot.version> <pamirs.distribution.version>4.7.8.5</pamirs.distribution.version> <!– 平台功能 –> <pamirs.metadata.manager>4.7.8</pamirs.metadata.manager> <pamirs.core.version>4.7.8.22</pamirs.core.version> <pamirs.workflow.version>4.7.8.16</pamirs.workflow.version> <pamirs.workbench.version>4.7.8</pamirs.workbench.version> <pamirs.data.visualization.version>4.7.8.1</pamirs.data.visualization.version> <!– 设计器 –> <pamirs.designer.common.version>4.7.8</pamirs.designer.common.version> <pamirs.flow.designer.base.version>4.7.8.1</pamirs.flow.designer.base.version> <pamirs.workflow.designer.version>4.7.8</pamirs.workflow.designer.version> <pamirs.model.designer.version>4.7.8</pamirs.model.designer.version> <pamirs.ui.designer.version>4.7.8.9</pamirs.ui.designer.version> <pamirs.data.designer.version>4.7.8</pamirs.data.designer.version> <pamirs.dataflow.designer.version>4.7.8.1</pamirs.dataflow.designer.version> <pamirs.eip.designer.version>4.7.8.1</pamirs.eip.designer.version> 注意镜像名称变化 体验镜像:(所有中间件及前后端服务,包含全部设计器)docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8:4.8.22 部署镜像:(包含前后端服务,包含全部设计器)docker pull harbor.oinone.top/oinone/oinone-designer-mini-v4.8:4.8.22 流程设计器镜像:(包含前后端服务,仅包含流程设计器)docker pull harbor.oinone.top/oinone/workflow-designer-v4.8:4.8.22 流程设计器镜像:(包含前后端服务,仅包含流程设计器,非外部库镜像)docker pull harbor.oinone.top/oinone/workflow-designer-standard-v4.8:4.8.22 独立部署流程设计器JAR:(包含前后端服务,仅包含流程设计器)pamirs-workflow-designer-boot-4.8.22.jar 后端无代码设计器Jar包启动方法 如果您有任何问题、建议或反馈,请随时联系我们。为了获得最佳体验,请及时更新至最新版本。我们将继续努力改进产品,提供更好的服务。谢谢!

    2024年12月20日
    1.6K00
  • 集成设计器数据流程、流程设计器可以暴露接口触发

    集成设计器数据流程暴露接口触发 需求:在集成设计器配置的连接器、数据流程链接到外部接口,需要可以有一个管理页面,统一管理这些集成配置。比如对接多个医院的挂号系统,希望可以配置好数据流程之后,能够在已经实现的开放接口上,动态的调用集成平台配置的数据流程。 连接器暴露接口触发 设计连接器资源配置模型。使用业务ID+接口唯一标识+连接器实现连接器资源和业务唯一。 @Model.model(EipConnectorResourceSetting.MODEL_MODEL) @Model(displayName = "连接器资源配置", summary = "连接器资源配置") @Model.Advanced(unique = {"hospitalId, interfaceUnique"}) public class EipConnectorResourceSetting extends IdModel { public static final String MODEL_MODEL = "hr.simple.EipConnectorResourceSetting"; @UxTableSearch.FieldWidget(@UxWidget()) @Field(displayName = "医院", required = true) @Field.Relation(relationFields = {"hospitalId"}, referenceFields = {"id"}) private Hospital hospital; @Field.Integer @Field(displayName = "医院ID", invisible = true) private Long hospitalId; @UxTableSearch.FieldWidget(@UxWidget()) @Field.String @Field(displayName = "接口唯一标识", required = true) private String interfaceUnique; @UxTableSearch.FieldWidget(@UxWidget()) @Field.many2one @Field(displayName = "连接器", required = true) @Field.Relation(relationFields = {"connectorId"}, referenceFields = {"id"}) private EipConnector connector; @Field.Integer @Field(displayName = "连接器ID", invisible = true) private Long connectorId; @UxTableSearch.FieldWidget(@UxWidget()) @Field.many2one @Field(displayName = "连接器接口", required = true) @Field.Relation(relationFields = {"integrationInterfaceId"}, referenceFields = {"id"}, domain = "connectorId==${activeRecord.connector.id}") private EipConnectorResource connectorResource; @Field.Integer @Field(displayName = "连接器接口ID", invisible = true) private Long connectorResourceId; } 开放接口定义,文档参考:https://doc.oinone.top/oio4/9326.html外部平台调用开放接口,实现动态调用连接器资源 @Model.model(HospitalSection.MODEL_MODEL) @Model(displayName = "医院科室", summary = "医院科室") public class HospitalSection extends IdModel { public static final String MODEL_MODEL = "net.example.HospitalSection"; @Field(displayName = "科室Code", required = true) private String deptCode; @Field(displayName = "科室名称", required = true) private String deptName; @Field(displayName = "科室描述") private String deptDesc; } @Slf4j @Fun @Component public class TestOpenService { @Resource private TestCommonService testCommonService;…

    2025年4月21日
    1.1K00
  • 【界面设计器】自定义字段组件实战——千分位输入框

    阅读之前 此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 业务背景 用户在输入【金额】字段时,实时展示千分位格式。 业务分析 从需求来看,我们需要实现一个【千分位】组件,并且该组件允许在【表单】视图中使用。 扩展实现:该组件虽然仅要求在【表单】中使用,但也可以在【搜索】中使用完全相同的实现,因此这里我们在注册时会增加【搜索】视图,将【千分位】组件应用在【搜索】中。对于【表格】、【详情】和【画廊】来说,该组件是没有【输入】行为的展示组件,在这里我们不进行演示。 准备工作 此处你应该已经在某个业务模型下,可以完整执行当前模型的全部【增删改查】操作。 业务模型定义 (以下仅展示本文章用到的模型字段,忽略其他无关字段。) 名称 API名称 业务类型 是否多值 长度(单值长度) 编码 code 文本 否 128 名称 name 文本 否 128 金额 money 金额 否 – 创建组件、元件 准备工作完成后,我们需要根据【业务背景】确定【组件】以及【元件】相关信息,并在【界面设计器】中进行创建。 以下操作过程将省略详细步骤,仅展示可能需要确认的关键页面。 创建千分位组件 创建千分位元件 启动SDK工程进行组件基本功能开发 (npm相关操作请自行查看SDK工程中内置的README.MD) 关键点详解 数据交互类型的字段组件(以下简称展示组件)与仅展示类型的字段组件(以下简称交互组件)有一些差别。 通常情况下,在展示组件中仅需使用value属性即可展示相关内容。在交互组件中除了value用于展示外,还需使用change、focus以及blur处理用户输入时的基本交互逻辑。 数据交互方法主要功能说明: change方法:当值发生变更时调用,根据字段相关配置将值回填至表单中。 focus方法:当组件获取焦点时调用,记录当前值,并在调用blur方法时进行处理。 blur方法:当前组件失去焦点时调用,根据focus方法记录的值,进行失焦触发逻辑的执行。 这里的三个数据交互方法仅仅是对用户行为的抽象,而并非限定其使用场景。 通常来说,这三个方法的调用顺序为:focus –> change –> blur。 如在日期时间组件中,面板打开时调用了focus方法,面板值发生变更时,调用了change方法,面板关闭时调用了blur方法。 如在地图组件中,选中地图上的某个点时仅会调用change方法,用户交互上并不能体现出focus和blur的行为。因此对于这个组件而言,只会有change方法被执行。 代码实现参考 PS:oio-input-number样式必须升级到4.6.x以上的最新版本才支持 Thousandth.vue <template> <a-input-number class=”oio-input-number” :value=”inputValue” :formatter=”formatter” :parser=”parser” @update:value=”change” @focus=”focus” @blur=”blur” /> </template> <script lang=”ts”> import { InputNumber as AInputNumber } from ‘ant-design-vue’; import { computed, defineComponent } from ‘vue’; export default defineComponent({ name: ‘Thousandth’, components: { AInputNumber }, props: { value: { type: [String, Number] }, change: { type: Function }, focus: { type: Function }, blur: { type: Function } }, setup(props) { const inputValue = computed(() => { return props.value; }); const formatter = (value) => { return <span class="hljs-subst">${value}</span>.replace(/\B(?=(\d{3})+(?!\d))/g, ‘,’); }; const parser = (value) => { return value.replace(/\$\s?|(,*)/g, ”); }; return { inputValue, formatter, parser }; } }); </script> FormMoneyThousandthFieldWidget.ts import { FormFieldWidget, ModelFieldType, SPI, ViewType } from ‘@kunlun/dependencies’; import Thousandth from ‘./Thousandth.vue’; @SPI.ClassFactory( FormFieldWidget.Token({ viewType: [ViewType.Form, ViewType.Search], ttype: ModelFieldType.Currency,…

    2023年11月1日
    1.5K00

Leave a Reply

Please Login to Comment