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

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

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

    腾讯云最新优惠活动来了:云产品限时1折,云服务器低至88元/年 ,点击这里立即抢购:9i0i.cn/qcloud,更有2860元代金券免费领取,付款直接抵现金用,点击这里立即领取:9i0i.cn/qcloudquan

    (福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

    大概是这样,一个积分表 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   ·   我们的愿景   ·   实用小工具   ·   2562 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:11 · PVG 21:11 · LAX 06:11 · JFK 09:11
    Developed with CodeLauncher
    ? Do have faith in what you're doing.


    http://www.vxiaotou.com