一个关于 SELECT COUNT(id) 的初级问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Livid
241.57D
593.51D
V2EX    PostgreSQL

一个关于 SELECT COUNT(id) 的初级问题

  •  
  •   Livid
    PRO
    2019-08-12 13:25:28 +08:00 8019 次点击
    这是一个创建于 2330 天前的主题,其中的信息可能已经有所发展或是发生改变。

    发现像下面这样的查询,希望获得一张表里的记录总数,在表的数据量比较大(上亿)的情况下,PostgreSQL 是无法马上返回结果的,需要等几十秒。有什么更好的方法么?

    SELECT COUNT(id) FROM table 
    26 条回复    2020-01-02 16:43:54 +08:00
    myyou
        1
    myyou  
       2019-08-12 13:28:22 +08:00
    上亿的话分表的,对每个表进行 count 汇总不知道会不会快一点
    Hermann
        2
    Hermann  
       2019-08-12 13:28:29 +08:00
    pg_class
    ipwx
        3
    ipwx  
       2019-08-12 13:28:31 +08:00 via Android
    count(1) count(*) 这两种写法的耗时呢?
    lihongming
        4
    lihongming  
       2019-08-12 13:29:24 +08:00 via iPhone
    理论上 COUNT(*)更快,因为 COUNT(id)要检查有没有 id,id 为 null 的不计数,而*不检查
    df4VW
        5
    df4VW  
       2019-08-12 13:30:48 +08:00
    @ipwx postgres 的话,count(*) 更快
    itskingname
        6
    itskingname  
       2019-08-12 13:31:11 +08:00
    @lihongming 如果 id 是主键的话,它就不会检查了吧。
    rio
        7
    rio  
       2019-08-12 13:34:21 +08:00   4
    df4VW
        8
    df4VW  
       2019-08-12 13:37:12 +08:00
    @rio 这里面说的其实都有点过时,现在都是 redis 里放一份就都解决了
    zeraba
        9
    zeraba  
       2019-08-12 13:43:51 +08:00 via Android
    看需求,如果这个值必须并且需要精确计算,定期统计后存聚合以后的值,或者插入就更新都是可选方案,如果是估算,可以直接用估算值,当然也可以估算之后再精确算
    wph95
        10
    wph95  
       2019-08-12 13:49:07 +08:00
    如果只是想知道一张表里的记录总数,用 pg_class 里的 reltuples 是最快的 常量级别。EXPLAIN 用的就是这个参数,开销极小。但是这个值存在误差的可能。
    想要精准结果 count(*) 最快
    rio
        11
    rio  
       2019-08-12 13:53:50 +08:00
    @df4VW 放 redis 的话一致性问题怎么解决?当然要看具体场景对数据准确性和可用性的要求。
    kingwl
        12
    kingwl  
       2019-08-12 14:21:13 +08:00
    @ipwx
    我记得是一样的 这个 case 在列裁剪的时候大概能干掉
    gz911122
        13
    gz911122  
       2019-08-12 14:21:39 +08:00
    EXPLAIN 取结果,不过有误差
    Raymon111111
        14
    Raymon111111  
       2019-08-12 14:27:50 +08:00
    需要精准的数据就离线跑吧
    quickma
        15
    quickma  
       2019-08-12 14:39:38 +08:00
    4 楼的说法是正确的,不过是 mysql 里的,至于 PostgreSQL 是不是也是一样的,我猜是一样的
    razertory
        16
    razertory  
       2019-08-12 14:43:53 +08:00
    大多数关系型数据库的存储引擎都是行存,做精准行数统计的时候多数是很慢的。如果说不需要精准那么用一些自带的函数可以改善。还有就是可以考虑用列存储引擎,或者用 Redis 做个 counter。
    oatw
        17
    oatw  
       2019-08-12 14:58:06 +08:00
    额,如果只是要统计一个表里的记录数量,是不是可以在写入数据的时候就把数量+1,在 Rails 里好像就是这么处理的,说的不对不要打我,我只是个小前端来 drop the beat。。。
    Mazexal
        18
    Mazexal  
       2019-08-12 15:17:35 +08:00
    我觉得如果不是要精确数据的话, 可以每隔一分钟跑一次任务, 然后缓存起来, 每次就获取最近的一次就好了
    Muninn
        19
    Muninn  
       2019-08-12 16:06:24 +08:00
    一般来说需要的都不是精确数据,那就再专门做一个低精度的缓存就好。

    控制所有插入和删除的地方,有动作时在别的地方维护总数;或者隔一段时间跑一次。二选一吧。
    nekoneko
        20
    nekoneko  
       2019-08-12 16:08:54 +08:00
    只知道 mysql 的 myisam 引擎会把一张表的行数存起来,查的时候秒出
    glacer
        21
    glacer  
       2019-08-12 19:34:02 +08:00
    不需要实时精确数据的话,就是存缓存定时更新。
    还有一种做法就是取 Explain 的 rows。
    starsriver
        22
    starsriver  
       2019-08-13 00:43:54 +08:00 via Android
    cache 阿,没见过这么统计的。
    est
        23
    est  
       2019-08-13 11:49:29 +08:00
    这事儿刚好也遇到过。楼上很多已经给出回答了,我具体说下,就是 EXPLAIN SELECT COUNT(id) FROM table 去看 rows 那一行返回。预估的。有误差。
    lolizeppelin
        24
    lolizeppelin  
       2019-09-07 18:42:40 +08:00
    @est 要加 where 过滤咋办 233333
    est
        25
    est  
       2019-09-07 19:12:22 +08:00
    @lolizeppelin 那就直接加上咯
    encro
        26
    encro  
       2020-01-02 16:43:54 +08:00
    升级 12,据说有优化,包括对 where 过滤
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5162 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 98ms UTC 01:31 PVG 09:31 LAX 17:31 JFK 20:31
    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