下面两条 SQL 语句哪个效率更高? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
imherer
V2EX    PostgreSQL

下面两条 SQL 语句哪个效率更高?

  •  
  •   imherer 2019 年 6 月 24 日 9530 次点击
    这是一个创建于 2421 天前的主题,其中的信息可能已经有所发展或是发生改变。

    表结构如下: uid,rid,name,home,event,data,time

    其中 uid 和 rid 联合唯一索引

    假如现在表里有接近 100W 行数据,其中每个 uid 大概有 10 行记录

    现要查询出单个 uid 下的最大 rid,下面哪个 SQL 语句效率更高呢?

    1.SELECT MAX(rid) AS rid FROM table WHERE uid = $1

    2.SELECT rid FROM table WHERE uid = $1 ORDER BY rid DESC LIMIT 1

    数据库为:PostgreSQL

    另外像这样的表结构没有主键性能上会有什么问题吗?(因为主键是用不到的)

    34 条回复    2019-06-25 10:44:37 +08:00
    8355
        1
    8355  
       2019 年 6 月 24 日   1
    我认为应该是 1
    ckaiii
        2
    ckaiii  
       2019 年 6 月 24 日   1
    1
    luoyou1014
        3
    luoyou1014  
       2019 年 6 月 24 日   2
    亲,你有数据直接到数据库里面执行 sql 验证下,比我们验证快多了。。。
    kisshere
        4
    kisshere  
       2019 年 6 月 24 日
    如果 2 很有用的情况,还发明 MAX 函数搞啥,所以,我站 1
    linbiaye
        5
    linbiaye  
       2019 年 6 月 24 日
    mysql 肯定是 1 了
    glacer
        6
    glacer  
       2019 年 6 月 24 日   4
    在存在(uid, rid)索引的情况下,rid 会按索引排序,两条语句的性能应该是接近的。
    如果没有索引,个人认为是 1,原因是 Max 函数取最大值的复杂度为 O(n),而排序的复杂度通常为 O(nlogn)。因此 max 函数的复杂度会低一些。
    ljpCN
        7
    ljpCN  
       2019 年 6 月 24 日 via Android
    一个是最大值,一个是排序,我想除非实现的人抽风了,不然明显最大值的复杂度只有 O(n)
    enenaaa
        8
    enenaaa  
       2019 年 6 月 24 日
    一样的 ,TOP 1 也是 O(n)
    zjp
        9
    zjp  
       2019 年 6 月 24 日 via Android
    PostgreSQL 的 explain 很强大,别浪费。
    另外按照语义写就是 1
    dog82
        10
    dog82  
       2019 年 6 月 24 日
    差不多一样,但是 1 明显更易懂!
    godlovesxcjtest
        11
    godlovesxcjtest  
       2019 年 6 月 24 日 via Android
    排序和求最大值复杂度会一样?一个是 O(N2),一个是 On,所以不是很明显吗
    sanggao
        12
    sanggao  
       2019 年 6 月 24 日 via iPhone   1
    我的天那,看了楼上几个回复!!!!
    no1xsyzy
        13
    no1xsyzy  
       2019 年 6 月 24 日
    SQL 的优化是数据库帮你完成的,不同的实现可能不同,不过我认为至少存在一个数据库软件这两者是等价的,甚至你写 2 都直接给你优化成 1 实现。
    那么,谁来试一下 PostgreSQL 的优化是否包含 ORDER DESC LIMIT 1 == Max ?
    不过如果没有该优化应该选 1 ;同时为了语义也应该选 1。我看不到选 2 的情况。
    CEBBCAT
        14
    CEBBCAT  
       2019 年 6 月 24 日 via Android
    @sanggao 老哥快别吊胃口了,说说楼上哪里有问题吧
    littlewing
        15
    littlewing  
       2019 年 6 月 24 日
    我的天那,看了楼上几个回复!!!!
    no1xsyzy
        16
    no1xsyzy  
       2019 年 6 月 24 日   1
    就当我口胡吧,似乎两者功能不完全等价。
    https://stackoverflow.com/questions/34246403/performance-of-max-vs-order-by-desc-limit-1
    ORDER BY DESC 会导致 NULL 在最前,所以有 NULL 的时候 2. 选出来的那个一定是 NULL。

    而该提问应该是没有索引导致的问题,而根据是否能选出至少一行(有 WHERE 所以不一定能找出来):
    找得出来的情况 ORDER BY DESC + LIMIT 1 效率比 MAX 高;
    找不出来的情况 MAX 效率极高。

    如果有索引我认为两者基本一致,因为不会需要进行一次排序。
    no1xsyzy
        17
    no1xsyzy  
       2019 年 6 月 24 日
    @no1xsyzy 好像建立了索引还是,刚没细读,搜不出来的情况 ORDER BY DESC + LIMIT 1 时间很长,用了 JOIN 就 1200ms 以上,写成子查询才保持始终最短时间。
    综上,A/B 测试吧。
    imherer
        18
    imherer  
    OP
       2019 年 6 月 24 日
    @glacer 确实是,我往表里插了 100W 数据,有(uid, rid)索引的情况下确实是一样的,差不多都是 38ms 左右
    WriteCloser
        19
    WriteCloser  
       2019 年 6 月 24 日
    看联合索引顺序
    如果是 rid 是左边那么用得着索引,如果在 MySQL innodb 里面索引默认就有顺序,所以不需要重复的排序这个过程
    我不清楚 max 里面的排序过程,但是不管怎样,语句二都不用排序了这么都比 1 性能更优吧

    所以
    1. 如果联合索引 rid,uid 语句 2 最优
    2. 建议设置主键索引,如果没有主键索引 innodb 内部也会帮你建立一个内部的,毕竟数据是放聚簇上的
    c4f36e5766583218
        20
    c4f36e5766583218  
       2019 年 6 月 24 日
    1. 取某一列的最大值,最小值
    min/max vs order by: https://stackoverflow.com/questions/426731/min-max-vs-order-by-and-limit
    2. 取某一列值,移除重复项
    DISTINCT vs GROUP BY: https://blog.csdn.net/ljl890705/article/details/70602442
    我觉得吧,看你需求,如果只是简单的取最大 /小值或者去重,还是用原生函数较好。毕竟不是 order-by,group-by 的本意。
    carlclone
        21
    carlclone  
       2019 年 6 月 24 日
    感觉是一样的 , uid 确认的情况下 rid 是有序的 , 并不需要再排序
    polymerdg
        22
    polymerdg  
       2019 年 6 月 24 日
    MYSQL 第一种
    MetoYou
        23
    MetoYou  
       2019 年 6 月 24 日
    有索引能命中应该是一样的,没索引应该是 1 快
    Aruforce
        24
    Aruforce  
       2019 年 6 月 24 日
    UID,RID 联合索引应该是有顺序的...
    大概类似于..这个结构
    ```
    BPTree{
    NODE uid; //uid 里面有一个 RID 的系列节点 array []形式?。。而这些节点是在插入时就排好序的...
    }
    ```
    这个两种实现速度上应该没什么区别才对...

    1 的更容易看出意思来...
    javlib
        25
    javlib  
       2019 年 6 月 24 日 via Android
    用 explain 看看呢? pg 的 explain 应该可以给出优化后的执行 plan
    maierhuang
        26
    maierhuang  
       2019 年 6 月 24 日
    一个字段上有索引的情况下两种执行计划是一致的,如果是无索引(或则楼主这种联合索引 rid 在后的情况下),max ( rid )走全表扫描,order by 这种需要 sort。
    leishi1313
        27
    leishi1313  
       2019 年 6 月 25 日 via Android
    与其盲猜,不如用 EXPLAIN ANALYZE 在表上跑一下不就知道了嘛
    applehater
        28
    applehater  
       2019 年 6 月 25 日
    怎么禁用缓存?
    Iamnotfish
        29
    Iamnotfish  
       2019 年 6 月 25 日
    哈,这个楼主如果用的是 SQL 的话我刚测过。160W 条数据,用 MAX 的话是比 DESC LIMIT 1 要快的,大概快十几 MS,不过不确定是不是因为有缓存了才是这样的结果。
    wd
        30
    wd  
       2019 年 6 月 25 日 via iPhone
    where 部分过滤之后,后续的动作不就是那 10 条记录的操作了么,这有啥好比的。
    gavinjou818
        31
    gavinjou818  
       2019 年 6 月 25 日 via iPhone
    我感觉都差不多,假如要纠结...是不是 limit1 多了一个操作
    ColoThor
        32
    ColoThor  
       2019 年 6 月 25 日
    max 不需要排序吧,性能应该更好?
    zclHIT
        33
    zclHIT  
       2019 年 6 月 25 日
    mysql 是 1,但是你不是有数据库么。。直接在真实数据中执行一下就能看到了啊。。。
    clarkyi
        34
    clarkyi  
       2019 年 6 月 25 日
    SQL1 执行 explain 得到的结果
    QUERY PLAN
    Aggregate (cost=2582.44..2582.45 rows=1 width=4)
    -> Index Scan using idx_table_uid on table_name (cost=0.57..2580.40 rows=815 width=4)
    Index Cond: ((uid)::text = '$id'::text)


    SQL2 执行得到的结果
    Limit (cost=2584.48..2584.48 rows=1 width=4)
    -> Sort (cost=2584.48..2586.51 rows=815 width=4)
    Sort Key: id
    -> Index Scan using idx_table_uid on table_name (cost=0.57..2580.40 rows=815 width=4)
    Index Cond: ((uid)::text = '$id'::text)

    数据总量在 1.4 亿左右,uid 是索引,感觉两条数据所花费的时间差不多
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2009 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 09:34 PVG 17:34 LAX 01:34 JFK 04:34
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86