深度分页问题优化方案

问题原因

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.13版本升级说明-20240601

    版本号: 4.7.8.13版本发布日期:2024.06.01更新要点:支持nacos作为dubbo注册中心 4.7.8.13版本 升级内容 修复界面设计器日期时间格式化显示错误的问题 支持nacos作为dubbo注册中心 EIP阶段获取的数据结果额外存储到另一张表 版本包信息 未使用到的版本号请忽略,按项目中使用到的进行替换 <!– 平台基础 –> <pamirs.middleware.version>4.7.8.3</pamirs.middleware.version> <pamirs.k2.version>4.7.8.5</pamirs.k2.version> <pamirs.framework.version>4.7.8.11</pamirs.framework.version> <pamirs.boot.version>4.7.8.8</pamirs.boot.version> <pamirs.distribution.version>4.7.8.3</pamirs.distribution.version> <!– 平台功能 –> <pamirs.metadata.manager>4.7.8</pamirs.metadata.manager> <pamirs.core.version>4.7.8.10</pamirs.core.version> <pamirs.workflow.version>4.7.8.9</pamirs.workflow.version> <pamirs.workbench.version>4.7.8</pamirs.workbench.version> <pamirs.data.visualization.version>4.7.8</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.7</pamirs.ui.designer.version> <pamirs.data.designer.version>4.7.8</pamirs.data.designer.version> <pamirs.dataflow.designer.version>4.7.8</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.5.7 部署镜像:(包含前后端服务,包含全部设计器)docker pull harbor.oinone.top/oinone/oinone-designer-mini-v4.8:4.8.5.7 流程设计器镜像:(包含前后端服务,仅包含流程设计器)docker pull harbor.oinone.top/oinone/workflow-designer-v4.8:4.8.5.7 流程设计器镜像:(包含前后端服务,仅包含流程设计器,非外部库镜像)docker pull harbor.oinone.top/oinone/workflow-designer-standard-v4.8:4.8.5.7 独立部署流程设计器JAR:(包含前后端服务,仅包含流程设计器)pamirs-workflow-designer-boot-4.8.5.7.jar 后端无代码设计器Jar包启动方法 如果您有任何问题、建议或反馈,请随时联系我们。为了获得最佳体验,请及时更新至最新版本。我们将继续努力改进产品,提供更好的服务。谢谢!

    2024年6月1日
    1.3K00
  • 3.5.7.7 自定义主题

    主题是什么 Oinone框架提供了强大的主题定制功能,使得平台可以轻松适应和遵循公司的品牌和UI规范。通过自定义主题,你可以调整颜色、间距、圆角等视觉元素,从而使Oinone更好地融入到特定行业的需求和公司标准中。以下是关于如何定制主题的关键点和步骤: 关键点 使用CSS变量: Oinone使用CSS变量 (Css Var) 来实现主题定制。 CSS变量提供了一种高效且灵活的方式来定义和使用样式。 全面定制: 可以定制的范围广泛,包括颜色、字体、间距、边框、圆角等。 通过调整这些元素,可以确保UI符合公司的视觉标准。 定制步骤 了解CSS变量: 首先,了解如何在CSS中使用变量。 查看Oinone现有的CSS变量列表,以了解哪些样式可以被定制。 定义公司的UI规范: 根据公司的品牌指南,定义一套UI规范。 包括颜色方案、字体样式、元素尺寸等。 应用自定义样式: 在Oinone的样式表中,使用定义的CSS变量来覆盖默认样式。 确保在适当的地方应用这些自定义样式。 作用场景 Oinone平台提供了灵活的主题定制选项,包括内置的六套主题样式,涵盖深色和浅色模式以及不同的尺寸选项(大、中、小)。这些主题可以适应不同的业务需求和项目特性,同时提供了定制工具,方便用户根据公司的UI规范进行调整。下面是主题作用场景的详细说明: 主题选项 内置主题: 六套主题:包括深色和浅色模式,以及大、中、小尺寸。 用户可以通过系统设置功能轻松切换不同的主题。 可定制性: 提供CSS变量的JSON文件,方便用户下载和修改。 允许用户根据具体需求定制颜色、字体、间距等样式变量。 应用场景 公司UI规范对齐: 首先根据公司的UI规范调整一份基础主题。 这有助于确保平台的外观与公司品牌一致。 项目和业务适应性: 在不同项目或业务场景中,可以基于公司UI规范进行微调。 这提供了项目特定的灵活性,同时保持整体的品牌一致性。 实施建议 初始设置: 初始时,选择一个接近公司标准的内置主题作为起点。 通过系统设置功能体验不同的主题效果。 定制和微调: 下载并修改CSS变量的JSON文件,以符合公司的UI标准。 对于特定项目或业务场景,根据需要进行进一步的微调。 自定义主题 自定义主题功能允许在Oinone平台上创建和应用独特的视觉风格,以适应特定的业务需求和品牌标准。以下是自定义主题的步骤和示例,用于指导如何在Oinone平台上实现这一功能。 示例工程目录 以下是需关注的工程目录示例,main.ts更新导入./theme: 图3-5-7-24 自定义主题目录示例 步骤 1: 创建主题 定义主题变量: 创建一个包含主题样式变量的JavaScript文件。例如,可以定义一个名为OinoneTheme的新主题,并设置相应的CSS变量。 图3-5-7-24 自定义主题代码示例 注册主题: 使用registerTheme函数注册自定义主题。这个函数将新主题添加到可用主题列表中。 步骤 2: 应用主题 在主入口文件中引用: 在main.ts文件中引入自定义主题,并在VueOioProvider配置中指定。 图3-5-7-24 自定义主题应用配置示例 效果 图3-5-7-24 自定义黑色主题效果示例 主题叠加: Oinone支持多个主题变量同时存在,后导入的主题变量会覆盖前面导入的。 内置主题 Oinone平台内置了以下六个主题变量,你可以在自定义主题时参考或扩展它们: ‘default – large’ ‘default – medium’ ‘default – small’ ‘dark – large’ ‘dark – medium’ ‘dark – small’ 扩展变量 在定义主题变量时,根据业务需求可以添加不存在的变量,作为变量的扩展。 示例 { "custom-color": "#新的辅助颜色", "button-padding": "10px 20px", // …其他自定义变量 } 图3 – 5 – 7 – 24 扩展主题变量 查找主题变量 在Oinone平台上,通过DOM调试器查找主题变量是一种有效的方式,允许用户定位并获取相应组件的主题变量。以下是执行这一步骤的详细说明: 步骤: 使用DOM调试器: 在浏览器中打开Oinone平台,进入需要查找主题变量的页面。 使用浏览器的开发者工具或DOM调试器(通常可通过右键点击页面元素并选择“检查”打开)。 选择目标组件: 在DOM调试器中,通过选择器工具或直接点击页面上的组件,选中你想要查找主题变量的目标组件。 查看样式和主题变量: 在选中的组件上,浏览开发者工具中的“样式”或“计算”选项卡。 可以通过查看样式表中的相关样式规则,找到组件所使用的主题变量。 4标识主题变量: 主题变量通常以 –oio 为前缀。标识出你感兴趣的主题变量,记录下变量名和当前的取值。 示例: 假设你想查找某个按钮组件的主题变量,可以通过以下步骤: 在DOM调试器中选中按钮组件。 在“样式”或“计算”选项卡中查看相关样式规则。 找到以 –oio 为前缀的主题变量,如 –oio-button-pirmary-background。 记录该主题变量的取值,例如 #3498db。 图3-5-7-24 DOM调试器查询主题变量

    2024年5月23日
    1.9K00
  • Nacos做为注册中心:如何调用其他系统的SpringCloud服务?

    Oinone项目引入Nacos作为注册中心,调用外部的SpringCloud服务 Nacos可以做为注册中心,提供给Dubbo和SpringCloud等微服务框架使用。 目前Oinone的底层使用的是Dubbo进行微服务的默认协议调用,但是我们项目如果存在需要调用其他系统提供的SpringCloud服务,Oinone其实并没有限制大家去这么写代码。 可以参考Nacos或SpringCloud的官方文档,只要不存在Jar包冲突等场景,很多的扩展其实大家都可以使用。 注意!!!Nacos、SpringCloud、SpringCloudAlibaba是有依赖版本严格要求的:点击查看 具体示例: 一、项目中增加依赖 主pom引入兼容的版本: <dependencyManagement> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.7.RELEASE</version> <!– 目前兼容的版本 –> <type>pom</type> <scope>import</scope> </dependency> </dependencyManagement> 使用模块的pom引入依赖: <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 二、 配置 application.yml spring: cloud: nacos: discovery: server-addr: localhost:8848 username: nacos password: nacos 三、启动类添加注解 @EnableDiscoveryClient @EnableFeignClients public class NacosConsumerApplication { public static void main(String[] args) { SpringApplication.run(NacosConsumerApplication.class, args); } } 四、验证 创建 Feign Client 接口 import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = "nacos-demo") // 指定目标服务的名称 public interface ProviderClient { @GetMapping("/hello") String hello(); } 创建 Controller 调用 Feign Client @RestController public class ConsumerController { private final ProviderClient providerClient; public ConsumerController(ProviderClient providerClient) { this.providerClient = providerClient; } @GetMapping("/hello") public String hello() { return providerClient.hello(); } } 在浏览器中访问 http://localhost:8082/hello你应该会看到服务提供者返回的响应。

    2024年6月4日
    3.4K00
  • 3.4.3.2 面向切面-拦截器

    一、拦截器 拦截器为平台满足条件的函数以非侵入方式根据优先级扩展函数执行前和执行后的逻辑。 使用方法上的@Hook注解可以标识方法为拦截器。前置扩展点需要实现HookBefore接口;后置扩展点需要实现HookAfter接口。入参包含当前拦截函数定义与该函数的入参。拦截器可以根据函数定义与入参增加处理逻辑。 拦截器分为前置拦截器和后置拦截器,前者的出入参为所拦截函数的入参,后者的出入参为所拦截函数的出参。可以使用@Hook注解或Hook模型的非必填字段module、model、fun、函数类型、active来筛选出对当前拦截方法所需要生效的拦截器。若未配置任何过滤属性,拦截器将对所有函数生效。 根据拦截器的优先级priority属性可以对拦截器的执行顺序进行调整。priority数字越小,越先执行。 二、前置拦截(举例) 增加一个前置拦截,对PetShop的sayHello函数进行前置拦截,修改函数的入参的shopName属性,在其前面增加"hookbefore:"字符串。并查看效果 Step1 新增PetShopSayHelloHookBefore实现HookBefore接口 为run方法增加@Hook注解 配置module={DemoModule.MODULE_MODULE},这里module代表的是执行模块,该Hook只匹配由DemoModule模块为发起入口的请求 配置model={PetShop.MODEL_MODEL},该Hook只匹配PetShop模型 配置fun={"sayHello"},该Hook只匹配函数编码为sayHello的函数 package pro.shushi.pamirs.demo.core.hook; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Hook; import pro.shushi.pamirs.meta.api.core.faas.HookBefore; import pro.shushi.pamirs.meta.api.dto.fun.Function; @Component public class PetShopSayHelloHookBefore implements HookBefore { @Override @Hook(module = {DemoModule.MODULE_MODULE},model = {PetShop.MODEL_MODEL},fun = {"sayHello"}) public Object run(Function function, Object… args) { if(args!=null && args[0]!=null){ PetShop arg = (PetShop)args[0]; arg.setShopName("hookbefore:"+ arg.getShopName()); } return args; } } 图3-4-3-5 新增PetShopSayHelloHookBefore实现HookBefore接口 Step2 重启查看效果 用graphQL工具Insomnia查看效果,如果访问提示未登陆,则请先登陆。详见3.4.1【构建第一个Function】一文 用 http://127.0.0.1:8090/pamirs/base 访问,结果我们会发现PetShopSayHelloHookBefore不起作用。是因为本次请求是以base模块作为发起模块,而我们用module={DemoModule.MODULE_MODULE}声明了该Hook只匹配由DemoModule模块为发起入口的请求 图3-4-3-6 示例效果 用 http://127.0.0.1:8090/pamirs/demoCore 访问,前端是以模块名作为访问入口不是模块编码这里大家要注意下 图3-4-3-7 示例效果 用 http://127.0.0.1:8090/pamirs/demoCore 访问,更换到petShop的子模型petShopProxy来访问sayHello函数,结果我们发现是没有效果的。因为配置model={PetShop.MODEL_MODEL},该Hook只匹配PetShop模型 三、后置拦截(举例) 增加一个后置拦截,对PetShop的sayHello函数进行后置拦截,修改函数的返回结果的shopName属性,在其后面增加"hookAfter:"字符串。并查看效果 Step1 新增PetShopSayHelloHookAfter实现HookAfter接口 为run方法增加@Hook注解 配置model={PetShop.MODEL_MODEL},该Hook只匹配PetShop模型 配置fun={"sayHello"},该Hook只匹配函数编码为sayHello的函数 package pro.shushi.pamirs.demo.core.hook; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Hook; import pro.shushi.pamirs.meta.api.core.faas.HookAfter; import pro.shushi.pamirs.meta.api.dto.fun.Function; @Component public class PetShopSayHelloHookAfter implements HookAfter { @Override @Hook(model = {PetShop.MODEL_MODEL},fun = {"sayHello"}) public Object run(Function function, Object ret) { if (ret == null) { return null; } PetShop result =null; if (ret instanceof Object[]) { Object[] rets = (Object[])((Object[])ret); if (rets.length == 1) { result = (PetShop)rets[0]; } } else { result = (PetShop)ret; } result.setShopName(result.getShopName()+":hookAfter"); return result; } } 3-4-3-8 新增PetShopSayHelloHookAfter实现HookAfter接口 Step2 重启查看效果 用 http://127.0.0.1:8090/pamirs/base 访问,结果我们会发现PetShopSayHelloHookAfter是起作用。PetShopSayHelloHookBefore没有配置模块过滤。 3-4-3-9 示例效果 用访问,结果我们会发现PetShopSayHelloHookAfte和PetShopSayHelloHookBefore同时起作用 3-4-3-10 示例效果 我们会发现HookAfter只对结果做了修改,所以message中可以看到hookbefore,但看不到hookAfter 四、注意点 不管前置拦截器,还是后置拦截器都可以配置多个,根据拦截器的优先级priority属性可以对拦截器的执行顺序进行调整。priority数字越小,越先执行。小伙伴们可以自行尝试 拦截器必须是jar依赖,不然执行会报错。特别是有的小伙伴配置了一个没有过滤条件的拦截器,就要非常小心 模块启动yml文件可以过滤不需要执行的hook,具体配置详见4.1.1【模块之yml文件结构详解】一文 调用入口不是由前端发起而是后端编程中直接调用,默认不会生效,如果要生效请参考4.1.9【函数之元位指令】一文

    2024年5月23日
    1.8K00
  • 4.1.17 框架之网关协议-GraphQL协议

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。 一个 GraphQL 服务是通过定义类型和类型上的字段来创建的,然后给每个类型上的每个字段提供解析函数。例如,一个 GraphQL 服务告诉我们当前登录用户是 me,这个用户的名称可能像这样: type Query { me: User } type User { id: ID name: String } 图4-1-17-1 GraphQL定义类型和字段示意 一并的还有每个类型上字段的解析函数: function Query_me(request) { return request.auth.user; } function User_name(user) { return user.getName(); } 图4-1-17-2 每个类型上字段的解析函数示意 一旦一个 GraphQL 服务运行起来(通常在 web 服务的一个 URL 上),它就能接收 GraphQL 查询,并验证和执行。接收到的查询首先会被检查确保它只引用了已定义的类型和字段,然后运行指定的解析函数来生成结果。 例如这个查询: { me { name } } 图4-1-17-3 GraphQL查询请求示意 会产生这样的JSON结果: { "me": { "name": "Luke Skywalker" } } 图4-1-17-4 GraphQL查询结果示意 了解更多 https://graphql.cn/learn/

    Oinone 7天入门到精通 2024年5月23日
    1.4K00

Leave a Reply

Please Login to Comment