码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 解决mysql深度分页问题


    目录

    1.基本分页:耗时0.019秒

    2.深度分页:耗时10.236秒

    3.深度ID分页:耗时0.052秒

    4.两步走深度分页:耗时0.049秒+0.017秒

    5.一步走深度分页:耗时0.05秒

    6.集成BeanSearcher框架

    7.万能优化技巧:索引。​编辑

    8. 如果对数据插入的要求很高,比如每秒插入十多条数据,还是每条逐个插入,时间久了必然数据量非常大。这里还有一个方法可以试一试,那就是牺牲事务而获取性能,对不重要的数据可以这么做。将InnoDB引擎改为MyISAM引擎。


    数据:单表数据25万条。

    1.基本分页:耗时0.019秒

    select * from cf_qb_info limit 0,20

    2.深度分页:耗时10.236秒

    select * from cf_qb_info limit 200000,20

    3.深度ID分页:耗时0.052秒

    提示:如果这一步很慢,count(1) 查询总数应该也会很慢-解决方式:请为主键加上unique索引。 

    1. -- 主键ID字段:NUMID
    2. select NUMID from cf_qb_info limit 200000,20

    4.两步走深度分页:耗时0.049秒+0.017秒

    基于第三步的缺陷(只能查出ID信息),我们可以先查出分页数据的ID,在根据ID查询数据。

    select NUMID from cf_qb_info LIMIT 200000,20
    1. select * from cf_qb_info where NUMID in (
    2. '330681650000202108180227345510',
    3. '330681650000202108171031534500',
    4. '330681650000202108190251532141',
    5. '330681650000202108200246376830',
    6. '330681650000202108210229398665',
    7. '330681650000202108220236113895',
    8. '330681650000202108230230034133',
    9. '330681650000202108231017279739',
    10. '330681650000202108231043456276',
    11. '330681650000202108231051404340',
    12. '330681650000202108240237397251',
    13. '330681650000202108250221489228',
    14. '330681650000202108250241536726',
    15. '330681650000202108260253039326',
    16. '330681650000202108270216016138',
    17. '330681650000202108280234013754',
    18. '330681650000202108290230029720',
    19. '330681650000202108300255579204',
    20. '330681650000202108310234184991',
    21. '330681650000202109010237315937'
    22. );

    两步合成一步SQL耗时:11.9秒;这一步着实出乎了我的意料。

    1. select * from cf_qb_info where NUMID in (
    2. select NUMID from (select NUMID from cf_qb_info LIMIT 200000,20) as t
    3. );

     鉴于这个结果:我们可以在程序里分成两步进行分页查询。

    5.一步走深度分页:耗时0.05秒

    这一步是对第四步的优化,毕竟两条SQL还需要码代码。利用join 两条SQL合成一条。

    1. SELECT
    2. *
    3. FROM
    4. cf_qb_info a
    5. JOIN ( SELECT NUMID FROM cf_qb_info LIMIT 200000, 20 ) b ON a.NUMID = b.NUMID

    6.集成BeanSearcher框架

    原理是使用了BeanSearcher的sql拦截器对SQL进行拦截改造。https://bs.zhxu.cn/guide/latest/advance.html#sql-%E6%8B%A6%E6%88%AA%E5%99%A8https://bs.zhxu.cn/guide/latest/advance.html#sql-%E6%8B%A6%E6%88%AA%E5%99%A8

     ①改造Bean

    ②注入Sql拦截器

    1. package com.ciih.qbbs.config;
    2. import cn.hutool.core.util.ReUtil;
    3. import cn.hutool.core.util.StrUtil;
    4. import com.baomidou.mybatisplus.annotation.TableId;
    5. import com.ejlchina.searcher.SearchSql;
    6. import com.ejlchina.searcher.SqlInterceptor;
    7. import com.ejlchina.searcher.SqlSnippet;
    8. import com.ejlchina.searcher.param.FetchType;
    9. import org.springframework.stereotype.Component;
    10. import java.lang.reflect.Field;
    11. import java.util.List;
    12. import java.util.Map;
    13. /**
    14. * BeanSearcher的Sql拦截器:优化深度分页
    15. *
    16. * @author sunziwen
    17. */
    18. @Component
    19. public class SqlInterceptorImpl implements SqlInterceptor {
    20. @Override
    21. public SearchSql intercept(SearchSql searchSql, Map paraMap, FetchType fetchType) {
    22. /**
    23. * 改造思路
    24. *
    25. * <>
    26. * 前:SELECT * FROM table1 t1 LIMIT 200000,20;
    27. * 后:SELECT * FROM table1 t1 JOIN ( SELECT id FROM table1 LIMIT 200000, 20 ) t99 ON t1.id = t99.id;
    28. *
    29. */
    30. Field[] fields = searchSql.getBeanMeta().getBeanClass().getDeclaredFields();
    31. String primaryColumnName = null;
    32. for (Field field : fields) {
    33. //这里使用了mybatis_plus的注解作为主键标识
    34. TableId tableId = field.getAnnotation(TableId.class);
    35. if (tableId != null) {
    36. if (!"".equals(tableId.value())) {
    37. primaryColumnName = tableId.value();
    38. } else {
    39. //驼峰转下划线
    40. primaryColumnName = StrUtil.toUnderlineCase(field.getName());
    41. }
    42. }
    43. }
    44. //如果没有主键标识,则不能进行SQL优化。
    45. if (primaryColumnName == null) {
    46. return searchSql;
    47. }
    48. //正则表达式获取where之后语句
    49. List limits = ReUtil.findAll("where[\\s\\S]*limit[ ]+[?]{1}[ ]*,[ ]+[?]{1}", searchSql.getListSqlString(), 0);
    50. //如果不分页,则不进行SQL优化,即语句中没有limit关键字不优化。
    51. if (limits.size() == 0) {
    52. return searchSql;
    53. }
    54. //表名小片段
    55. SqlSnippet tableSnippet = searchSql.getBeanMeta().getTableSnippet();
    56. //合成子查询SQL
    57. String inSql = "JOIN ( SELECT " + primaryColumnName + " FROM " + tableSnippet.getSql() + " " + limits.get(0) + " ) t99 ON t1." + primaryColumnName + " = t99." + primaryColumnName + ";";
    58. //合成整条SQL
    59. String replace = searchSql.getListSqlString().replace(limits.get(0), inSql);
    60. //替换
    61. searchSql.setListSqlString(replace);
    62. return searchSql;
    63. }
    64. }

    7.万能优化技巧:索引。

    8. 如果对数据插入的要求很高,比如每秒插入十多条数据,还是每条逐个插入,时间久了必然数据量非常大。这里还有一个方法可以试一试,那就是牺牲事务而获取性能,对不重要的数据可以这么做。将InnoDB引擎改为MyISAM引擎。

  • 相关阅读:
    代码源每日一题div1 贪心 线性筛 最小生成数
    曲线救国|基于函数计算FC3.0部署AI数字绘画stable-diffusion
    Safari 最新技术预览版来啦,为开发者带来了哪些新功能?
    如何把PDF文档转换成Word格式呢?
    studio3T import a SQL Database to Mongodb(从mysql中导入数据到mongodb)
    想当测试Leader,这6项技能你会吗?
    程序员面试代码
    [BSidesCF 2019]Kookie
    01.Go语言介绍
    扬帆际海:东南亚为何成为跨境消费天堂?
  • 原文地址:https://blog.csdn.net/wenxingchen/article/details/126540876
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号