sql连表优化心得

慢查询的 sql:

select
    `a` .*,
    `b`.`zgzdf_date` as `max_rate_date`
from
    (
    select
        `stockcode`,
        `stockname`,
        `shareholder_name`,
        max(zgzdf) as max_rate
    from
        `shareholder_battle_fund`
    where
        `shareholder_name` = '香港中央结算有限公司'
        and `stocktype` = 1
    group by
        `stockcode` 
    ) as a
inner join `shareholder_battle_fund` as `b` on
    `a`.`stockcode` = `b`.`stockcode`
    and `a`.`max_rate` = `b`.`zgzdf`
    and `b`.`shareholder_name` = `a`.`shareholder_name`
order by
        `max_rate` desc
limit 20 OFFSET 10

这条 sql 的本意是:按股票代码分组,取最大的涨跌幅,并将最大涨跌幅所在的日期一并取出,然后按涨跌幅排序进行分页。

优化思路就一条,缩减 join 表的大小:#

优化后的 sql:

select
    *
from
    (
    select
        `a` .*,
        `b`.`zgzdf_date` as `max_rate_date`
    from
        (
        select
            `stockcode`,
            `stockname`,
            `shareholder_name`,
            max(zgzdf) as max_rate
        from
            `shareholder_battle_fund`
        where
            `shareholder_name` = '香港中央结算有限公司'
            and `stocktype` = 1
        group by
            `stockcode`
        order by
            `max_rate` desc
        limit 20 OFFSET 10
    ) as a
    inner join `shareholder_battle_fund` as `b` on
        `a`.`stockcode` = `b`.`stockcode`
        and `a`.`max_rate` = `b`.`zgzdf`
    where
        `b`.`shareholder_name` = '香港中央结算有限公司') as c
order by
    `c`.`max_rate` desc

优化后的 sql 中,a 表被缩减至 20 条数据,b 表被 where 条件缩减掉一批数据。执行耗时由原来的 2200 毫秒,缩减至 149 毫秒。

sql
本作品采用《CC 协议》,转载必须注明作者和本文链接
梦想星辰大海
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 19

我最近也遇到这种,老系统上来就是 left join ,还有分组排序好多,慢的一批

11个月前 评论

但是 limit 了 结果还准确吗

11个月前 评论
梦想星辰大海 (楼主) 11个月前
梦想星辰大海 (楼主) 11个月前

你这个情况,应该能免去外层 JOIN?前提条件:

  1. zgzdf 能转换成 [-2 ^ 31, 2 ^ 31)
  2. zgzdf_date 是 32 位整数时间戳

大致是这样?

select
    `stockcode`,
    `stockname`,
    `shareholder_name`,
    max(转成32位整数(zgzdf) << 32 | zgzdf_date) as max_rate_and_date
from
    `shareholder_battle_fund`
where
    `shareholder_name` = '香港中央结算有限公司'
    and `stocktype` = 1
group by
    `stockcode`
order by
    `max_rate_and_date` desc
limit 20 OFFSET 10 

程序拿到数据后,高 32 位是转换后的涨跌幅(转回来就好),低 32 位是日期。

连表开销,应该远大于这点运算量吧。。

11个月前 评论
梦想星辰大海 (楼主) 10个月前
wxf666 (作者) 10个月前
代码已被折叠,点此展开
11个月前 评论
guanguans (作者) 10个月前
梦想星辰大海 (楼主) 10个月前
晏南风 10个月前
空山 10个月前

第一个 a 表全表查询了吧

11个月前 评论
梦想星辰大海 (楼主) 11个月前

扔到 chatgpt,让它帮你优化 :smile:

11个月前 评论
梦想星辰大海 (楼主) 10个月前

修改后,子查询的范围缩小了,提早进行选择 where 查询! :thumbsup:

11个月前 评论
select
    sbf.stockcode,
    sbf.stockname,
    sbf.shareholder_name,
    SUBSTRING_INDEX(GROUP_CONCAT(sbf.zgzdf order by sbf.zgzdf DESC), ',', 1) as max_rate,
    SUBSTRING_INDEX(GROUP_CONCAT(sbf.zgzdf_date order by sbf.zgzdf DESC), ',', 1) as max_rate_date
FROM
    shareholder_battle_fund sbf
WHERE
    shareholder_name  =  '香港中央结算有限公司'  and  stocktype  =  1
GROUP BY
    sbf.stockcode
ORDER BY
    sbf.max_rate desc
10个月前 评论