是派小星呀 2022-10-08 16:14 采纳率: 71.8%
浏览 151
已结题

pg数据库序列值问题

现在我有个user_test表,里面有个test_id字段,有个唯一字段user_id,现在想将test_id为0的记录置为一个序列值,假如我这个表记录有好几百万条,但我每次只想置1w条,有什么好的办法吗?执行的sql最好效率要高能走索引,因为数据量比较大


UPDATE user_test set test_id = nextval('user_test_id_seq') where test_id =0;

现在想实现的功能 :UPDATE user_test set test_id = nextval('user_test_id_seq') where test_id =0 limit 10000; 此段sql会报错
  • 写回答

4条回答 默认 最新

  • 游一游走一走 2022-10-08 16:24
    关注
    UPDATE user_test SET test_id= nextval('user_test_id_seq')
    WHERE user_id IN (
        SELECT user_id FROM (
            SELECT user_id FROM user_test
            where test_id =0 
            LIMIT 10000
        ) subquery
    );
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
  • 凯歌响起 2022-10-08 16:20
    关注

    postgresql不支持,update.....limit 这样的语法,所以可以这样。

    WITH cte AS (
       SELECT server_ip          -- pk column or any (set of) unique column(s)
       FROM   server_info
       WHERE  status = 'standby'
       LIMIT  1                  -- arbitrary pick (cheapest)
       )
    UPDATE server_info s
    SET    status = 'active' 
    FROM   cte
    WHERE  s.server_ip = cte.server_ip
    RETURNING server_ip;
    
    评论
  • 爱吃苦瓜的猿 2022-10-09 22:54
    关注

    提供一个思路。
    1.创建一个临时表,把要更新的user_id和序列号先放入这个临时表中

    create table tmp as
    select user_id,row_number() over(order by user_id) as test_id
    from user_test
    where test_id =0;
    

    2.写一个脚本去更新user_test,不断更新${offset}值,一致到更新完所有数据

    with t as (
      select user_id,test_id
      from tmp
      order by user_id
      limit 10000 offset ${offset}
    )
    update user_test
    set user_test.test_id=t.test_id
    from user_test,t
    where user_test.user_id=t.user_id
    
    评论 编辑记录
  • leaf_cq 2022-10-10 17:56
    关注

    1、首先,这个处理你是需要执行多少次?是手工执行还是程序执行?如果只执行几次或手工执行,慢一点是没有关系的,在 with t as 之后加上: MATERIALIZED 关键字即可节省执行时间,即:

    with t as MATERIALIZED ( select …… limit 10000 ) update ……  from …… where …… ;-- 具体见楼上各位的回答
    
    

    2、如果你需要长期在程序中执行,你就需要分析一下有索引的user_id字段的数据分布了,分别对其前n个字符进行统计:

    SELECT LEFT( user_id, n ) usr, count( 1 ) cnt FROM user_test WHERE test_id = 0 GROUP BY LEFT( user_id, n ); -- n需要从小到大的试
    

    当得到的cnt数量足够小(正好10000基本是不可能的,大于10000或分布比较平均即可),将usr字段的结果保存到程序中(估计user表的数据变化不会太大,一次统计应该能够满足一定时期的运行使用,运行一段时间后,再重复上面的分析即可),然后通过

     WHERE user_id like '前n个字符%' and test_id = 0 limit 10000
    

    来提取数据,这样可能会走索引,最终能否走索引还要看数据库的执行计划的对cost的最终判定,只有试了才知道……

      

    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 10月21日
  • 已采纳回答 10月13日
  • 修改了问题 10月8日
  • 修改了问题 10月8日
  • 展开全部

悬赏问题

  • ¥30 如何隐藏Tornado版本号
  • ¥15 PCL注册的选点等函数如何取消注册
  • ¥15 问一下各位,为什么我用蓝牙直接发送模拟输入的数据,接收端显示乱码呢,米思齐软件上usb串口显示正常的字符串呢?
  • ¥15 Python爬虫程序
  • ¥15 crypto 这种的应该怎么找flag?
  • ¥15 设计一个时序电路,使其状态按2421(B)循环,并能自启动
  • ¥15 代码已写好,求帮我指出错误,有偿!
  • ¥15 matlab+波形匹配算法
  • ¥15 转录组分析做聚类树图时癌旁组被分到了癌组
  • ¥15 大一Python字典