V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
sjmcefc2
V2EX  ›  Go 编程语言

请教 go 和 Python 逐行读文件,然后 insert 到数据库,哪个更快?

  •  
  •   sjmcefc2 · 2018-07-22 11:14:33 +08:00 · 4405 次点击
    这是一个创建于 2316 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 python 的 mmap 来读文件,insert 到数据库,总感觉速度特别慢? pgadmin4 显示每秒 600transaction,cpu 使用率也非常低,iostat 貌似才几十 k/s。 是语言问题? go 能更高效吗? 或者是数据库设置问题? 或者是 insert 方式问题? 如何才能机器性能完全释放,把 postgres 发挥到最大? 很多配置已经参考了德哥 blog。

    32 条回复    2018-07-23 14:27:37 +08:00
    ksupertu
        1
    ksupertu  
       2018-07-22 11:18:47 +08:00 via iPhone
    组批量插入,例如 5000 条一起插入,跟语言性能关联度不高
    daigouspy
        2
    daigouspy  
       2018-07-22 11:35:59 +08:00 via Android
    慢是因为数据库吧?
    liprais
        3
    liprais  
       2018-07-22 11:38:15 +08:00 via iPhone
    不要一条一条的插入,主流数据库都有批量导入的方法
    iwiki
        4
    iwiki  
       2018-07-22 11:41:19 +08:00
    如果可以的话开启事务,一次性提交
    reus
        5
    reus  
       2018-07-22 12:05:07 +08:00
    和语言关系不大,和你的数据库配置、插入方式关系大些
    你又不说具体的,没法判断是哪里有瓶颈
    est
        6
    est  
       2018-07-22 12:06:33 +08:00 via Android
    pg 导入最快的是 py 输出 csv 然后用 COPY
    sjmcefc2
        7
    sjmcefc2  
    OP
       2018-07-22 12:31:09 +08:00
    @reus 具体还需要哪些信息判断 /

    @daigouspy 是啊,也是觉得是数据库。但是具体哪里呢?
    @ksupertu 组批量?主要是不知道哪条有问题,这些数据有些是有问题的,一下 copy 批量的话,不知道怎么把有问题的数据跳出来。

    @liprais 使用了批量,这些余下的数据是有问题的数据,不知道哪条哪个字段就有问题了。这样的如何批量导入,还能把有问题的数据挑出来呢?
    @liprais
    @iwiki 这个开启事务倒是还没有试过。
    目前我是用 python 一条一条的 insert,遇到不能 insert 的就写在新文件里面。因为有些字段有问题,copy 会中断,我想知道哪些数据没有被插入,所以想了这么弱智的办法。
    n2ex2
        8
    n2ex2  
       2018-07-22 12:37:54 +08:00 via Android
    应该先把合格的数据筛选出来
    daigouspy
        9
    daigouspy  
       2018-07-22 12:39:47 +08:00 via Android
    @sjmcefc2 先把写入数据库的代码注释掉再运行就知道啦
    MonoLogueChi
        10
    MonoLogueChi  
       2018-07-22 13:12:43 +08:00 via Android
    你现在的瓶颈不是读取问题,和语言无关,要优化方法,一条一条 insert 用啥语言都不快
    zhs227
        11
    zhs227  
       2018-07-22 14:01:45 +08:00
    开事务,一次多 insert 一点,然后再提交事务。 一条一条提交的话每次都要重建索引这些。
    语言层面的速度差异应该不大,影响大的是数据库插入速度。
    xjmroot
        12
    xjmroot  
       2018-07-22 14:32:42 +08:00
    你这相当于是阻塞式的,一个 insert 完在处理下一个,没有用到并发呢。
    调整下程序逻辑,可以考虑下并发 insert
    limbo0
        13
    limbo0  
       2018-07-22 14:48:10 +08:00 via Android
    我是用 python 拼出 sql,然后批量导入 sql 就行了
    sjmcefc2
        14
    sjmcefc2  
    OP
       2018-07-22 14:57:07 +08:00
    @n2ex2 如何筛选呢?这个帅选的过程如何才能快?

    @MonoLogueChi 瓶颈不是读取,不是语言;不能一条一条 insert,具体要怎么优化方法呢?

    @zhs227 我现在是用 python 拼出 sql,但是我不知道这些拼出的 sql 哪些能够导入。如果分组( 5000 个一组)的话,倒是某些可能导入不了,但也能提高速度。问题我要知道哪些没有被导入。不知道是不是描述清楚了。

    @xjmroot 并发 insert ?能提供一个模版参考吗

    @limbo0 目前我用的就是 python 拼 sql,为了知道哪一条是坏数据,后面用的是逐条 insert。
    q2683252
        15
    q2683252  
       2018-07-22 14:57:09 +08:00
    用 python 拼出 sql,用 Copy 语法,然后 psql 导入,亲测单机 50w/s 以上 挤爆你带宽
    sjmcefc2
        16
    sjmcefc2  
    OP
       2018-07-22 15:01:27 +08:00
    @q2683252 假如 10w 条数据里面,中间一条或者 10 几条字段数据有问题,copy 出错,怎么处理?如何找到这几个错条?
    q2683252
        17
    q2683252  
       2018-07-22 15:04:33 +08:00
    @sjmcefc2 那为什么字段数据会有问题呢 你的意思是数据格式不对还是说数据内容需要和数据库中的内容交互验证?
    q2683252
        18
    q2683252  
       2018-07-22 15:08:07 +08:00
    @sjmcefc2 只有几条数据出错的话 可以等导入失败我就知道哪条数据有问题 然后用 vim 直接处理就可以了
    sjmcefc2
        19
    sjmcefc2  
    OP
       2018-07-22 15:15:10 +08:00
    @q2683252 部分是编码问题;比如数据库要求所有数据是 gbk,而某条数据的几个字段是其他乱七八糟的编码拼凑的;或者是数据库设计时候类型是 int,在数据这边就变成了其他的;总之,就是体现为 insert 失败,copy 失败等等;错误条目数量不确定,有的吧可能也就一条,有的可能整个文件都乱了。

    现在纠结在于如何快速导入,如何还能挑出(最好自动)不能导入的数据。
    现在采取的就是 python 拼 insert sql,然后逐条 insert,失败了就另写文件。
    sjmcefc2
        20
    sjmcefc2  
    OP
       2018-07-22 15:17:02 +08:00
    我用的是 psycopg2 这个包,copy,但是没有返回任何信息让我比较苦恼。不知道哪里 copy 错了。不知道大家都怎么处理这种情况。
    sjmcefc2
        21
    sjmcefc2  
    OP
       2018-07-22 15:19:34 +08:00
    @q2683252 另外这个单机 50w/s 是从哪里得出的数据?一直不知道怎么衡量性能。
    q2683252
        22
    q2683252  
       2018-07-22 15:24:06 +08:00
    @sjmcefc2 之前我自己导入过一些数据 50w 条我记得 几秒就好了 。
    有一个方法 ,你不需要知道哪条 copy 错了,因为每一个 copy 是一个事务,
    比如你批量 copy 5000 条 ,中间一条错了是吧,肯定是某一条开始出现问题,
    那么就试一下 copy2500 条,如果出现错误,那么错的数据肯定在 2500 条内。
    依次类推, 就是二分的思想
    limbo0
        23
    limbo0  
       2018-07-22 16:34:01 +08:00 via Android
    用 begin commit 事务,中间出错会 rollback,然后根据报错信息调整
    sjmcefc2
        24
    sjmcefc2  
    OP
       2018-07-22 19:02:40 +08:00
    @limbo0 貌似这样的话,很难用 python 程序自动处理啊,数据可能只有一条错,也可能整个文件都错了。
    FenGuWu
        25
    FenGuWu  
       2018-07-22 20:04:51 +08:00
    跟语言没有关系。我也遇到了一样的问题。我用 java。一个事务提交 1w 条。开始 iostat 只有 16k。后来用 12 个线程往里怼,io 提高到 176k,server cpu 吃满。
    hustlibraco
        26
    hustlibraco  
       2018-07-22 22:55:18 +08:00
    这种情况应该校验数据,使用数据库的批量导入方法,跟语言关系不大
    sjmcefc2
        27
    sjmcefc2  
    OP
       2018-07-22 22:58:34 +08:00
    @hustlibraco 很棒的思路啊。就是不知道如何校验数据,如何把能批量导入的弄出来,把不能批量的有错误数据弄出来。一个文件分成两个?
    bbbai
        28
    bbbai  
       2018-07-23 10:33:19 +08:00
    分组插入 一组 5000 条,然后多开几个线程就会快些,1000w 八线程我跑了 30 分钟
    sjmcefc2
        29
    sjmcefc2  
    OP
       2018-07-23 11:11:23 +08:00
    @bbbai 能分享一下代码吗?机器配置如何?
    YumeMichi
        30
    YumeMichi  
       2018-07-23 11:35:52 +08:00
    mysql 的话逐条 insert 肯定是很慢的 我以前的做法是每 5000 条 insert 合并成一条 这样能快很多 如果再加上多线程应该还能更快 但是因为 py 多线程这块当时没研究过 就只是用单线程跑的
    bbbai
        31
    bbbai  
       2018-07-23 12:04:13 +08:00
    ···
    insert_p = ("INSERT INTO a_b_v("name","num")" "VALUES(%s,%s)")
    for j in range(0,5000):

    data_p = ("admin","0001")
    data_p_list.append(data_cp)

    cursor.executemany(insert_p,data_p_list)
    db.commit()···
    @sjmcefc2 核心就是这样,数据表多,行列多可能会很繁琐,可以考虑在数据结构进行优化。python2
    Siglud
        32
    Siglud  
       2018-07-23 14:27:37 +08:00
    你这么写铁定慢,快速的写法是
    INSERT INTO a_b_v("name","num") VALUES (%s,%s),(%s,%s),(%s,%s)....
    后面拼 1000 条
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2562 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 10:44 · PVG 18:44 · LAX 02:44 · JFK 05:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.