zoukankan      html  css  js  c++  java
  • mysql分页查询优化(索引延迟关联)

    对于web后台报表导出是一种常见的功能点,实际对应服务后端即数据库的排序分页查询。如下示例为公司商户积分报表导出其中一个sql ,当大批量的导出请求进入时候,mysql的cpu急剧上升瞬间有拖垮库的风险。

    SELECT
        *
    FROM
        coupons.cp_score_log
    WHERE
        `m_shopid` = 40861
    AND `add_time` BETWEEN 1483200000
    AND 1544543999
    ORDER BY
        add_time DESC
    LIMIT 118000 ,1000 ;

    报表导出功能存在几个问题:

    1、时间跨度太大,数据量剧增。(可以结合业务需求,限制一定时间范围,比如只能导出3个月以内数据)

    2、DB方面没有限制并发。(需要dba一起参与)

    3、sql未考虑LIMIT分页过大,查询性能问题。(索引延迟关联,本文重点 或者 限制分页上限

    运行结果:18.94s (结果受到机器峰值影响,可能低一些,可能更高)

    sql执行计划 :

    表结构:

    CREATE TABLE `cp_score_log` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
       ......
      `m_shopid` int(10) DEFAULT '0' COMMENT '总店id',
       ......
      `add_time` int(10) DEFAULT '0',
      `......PRIMARY KEY (`id`),
      KEY `idx_cardno` (`card_no`),
      KEY `idx_shopid` (`shopid`) USING BTREE,
      KEY `idx_orderid` (`order_id`),
      KEY `idx_shopid_add_time_score` (`shopid`,`add_time`,`score`),
      KEY `idx_mshopid` (`m_shopid`,`add_time`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=24130302 DEFAULT CHARSET=utf8 COMMENT='积分记录表'

    表的数据基本在2400万左右未进行拆分,通过查看sql和执行计划发现已经命中索引【idx_mshopid】,但是查询效率仍然很低。抛开其他问题只针对sql来说,核心的问题出在LIMIT。

    MySQL中 【LIMIT offset, m】并不是跳过offset然后取m行数据,而是直接取【offset+m】行数据,丢弃前offset行返回m行。因此查询的效率就特别的低,特别当offset特别大的时候。

    针对上面提出第3点问题,可以考虑使用后索引延迟关联,即 通过建立中间表覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据。 同时限制最大的分页数量,比如百度最大分页即为79页 。

    SELECT
        *
    FROM
        cp_score_log
    INNER JOIN (
        SELECT
            id,
            add_time
        FROM
            coupons.cp_score_log
        WHERE
            `m_shopid` = 40861
        AND `add_time` BETWEEN 1483200000
        AND 1544543999
        ORDER BY
            add_time DESC
        LIMIT LIMIT 118000 ,1000
    ) b ON cp_score_log.id = b.id
    ORDER BY
        b.add_time DESC;

    运行结果:0.7s (天差地别)

     sql执行计划:

      由此可见,使用sql延迟关联sql效率确实提升明显。但是并非能解决所以问题,当表数据过大已经数据库并发提高时,还是会出现查询慢甚至拖垮db当风险。所以因综合考虑,将请求量削峰。

  • 相关阅读:
    Linux 使用 ssh 命令远程连接另一台 Linux
    高并发连接导致打开文件过多:java.io.IOException: Too many open files 解决方法
    WEB安全:Tomcat 只可通过域名访问,禁止通过 IP 访问
    Jmeter
    CentOS 7 开启 SNMP 实现服务器性能监控
    SSM框架、Druid连接池实现多数据源配置(已上线使用)
    Tomcat 服务器安装 SSL证书,实现 HTTP 自动跳转 HTTPS
    java操作远程共享目录
    jobss目录结构
    oracle中if/else的三种实现方式
  • 原文地址:https://www.cnblogs.com/xiaoxing/p/10106861.html
Copyright © 2011-2022 走看看