V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
luxinfl
V2EX  ›  程序员

现网的一个 sql 慢查询,不是很懂。

  •  
  •   luxinfl · 2022-11-29 14:21:29 +08:00 via Android · 2113 次点击
    这是一个创建于 724 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大概是这样,一个积分表 point ,我需要一次查询 100 个用户积分过期 expired 的数据。 表字段大概这样

    字段     类型     索引
    pointid varchar primary key
    expired varchar  index
    userid varchar index
    
    select userid from point where now()>= expired oser by id asc limit 0,100
    

    我修改成了

    select distinct userid from point a where exists (select userid from point b where a.userid =b.userid and now()>=expired )order by a.userid asc limit 0,100
    

    为啥修改后的查询时间要比修改前快了 100 倍,修改前 8s ,修改后 0.07s 。 执行计划,修改前:index rows 约等于 160w 修改后:一个 range ,300 ,using index for group-by ;一个 ref ,16000;

    第 1 条附言  ·  2022-11-30 14:26:23 +08:00
    我发现这玩意还和数据分布有关系,数据比较分散的快都挺慢的,感觉执行计划里面的 rows 不是很准。
    13 条回复    2022-11-30 05:17:29 +08:00
    plutome
        1
    plutome  
       2022-11-29 14:23:56 +08:00
    同不懂
    CEBBCAT
        2
    CEBBCAT  
       2022-11-29 14:28:28 +08:00
    第一个是先过滤出*所有*过期的,然后按照 id (也不知道你说的是哪个 id )排序,然后再取前一百

    后一个是在表上按照 userid 增序遍历,然后过滤出一百个后中止,返回结果

    我建议按照主键遍历,利用 where pointid>${上一批结果中最后一个结果的 ID},来过滤数据
    likunyan
        4
    likunyan  
       2022-11-29 14:42:19 +08:00
    第一条去掉 order by 看看
    eijnix
        5
    eijnix  
       2022-11-29 14:43:36 +08:00
    你是不是用的 mysql 5.6 版本? 如果是的话可能是 mysql 的 order by + limit 的一个坑, 你这里可以把第一个 sql 的 limit 放的很大试试
    前阵子写的: https://juejin.cn/post/7164423778033172517
    luxinfl
        6
    luxinfl  
    OP
       2022-11-29 15:00:44 +08:00
    @CEBBCAT 上一批结果是啥意思。。不过我看这个业务每次找到 100 个用户就行了,两次任务重复了也没关系。。
    luxinfl
        7
    luxinfl  
    OP
       2022-11-29 15:02:32 +08:00
    @likunyan 去掉也慢,而且改动了原来的逻辑,虽然这逻辑没卵用。。。
    chenqh
        8
    chenqh  
       2022-11-29 15:21:54 +08:00
    你这个应该是 order by 的问题吧,第二个是 order by user_id 不是 order by id 了
    chenqh
        9
    chenqh  
       2022-11-29 15:24:05 +08:00
    还有 explain 呢?
    CEBBCAT
        10
    CEBBCAT  
       2022-11-29 15:44:48 +08:00
    @luxinfl
    > 去掉也慢,而且改动了原来的逻辑,虽然这逻辑没卵用。。。
    那直接去掉不就好了,保持最简。

    > 上一批结果是啥意思。。不过我看这个业务每次找到 100 个用户就行了,两次任务重复了也没关系。。
    你不是要分批查询,每次一百个吗?上一批就是上次那 100 个中最后一行的 pointid 。你指定了 pointid ,之前扫描过的行就不会再扫描了。你说的这个“两次任务重复了也没关系”我倒是有点没明白,是查询到了之后会立即做删除,所以下次查询之前表里已经没有这批数据了吗?

    你得想想,怎么让整个任务周期中数据库引擎做尽量少的事。如果你每次都是从表的第一行开始查,那么你执行多少次 SQL ,第一行就得差多少词。这样的复杂度得奔 n^2 去了吧
    luxinfl
        11
    luxinfl  
    OP
       2022-11-29 19:44:22 +08:00
    @chenqh 这个纯属写错了,就是 userid
    luxinfl
        12
    luxinfl  
    OP
       2022-11-29 19:46:36 +08:00
    @CEBBCAT 这个定时任务只负责每次查 100 条满足的用户,貌似是加了锁,不会重复扫描到。。但是我后来又导入一批数据,发现 explain 一样,但是两条 sql 执行结果时间又差不多了。。。搞不懂
    qinrui
        13
    qinrui  
       2022-11-30 05:17:29 +08:00 via iPhone
    在第一句的 where 后面加上 1=1 and 试一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   939 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:18 · PVG 05:18 · LAX 13:18 · JFK 16:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.