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

关于大量数据导出到 excel 或 csv 实现方案

  •  
  •   imherer · 114 天前 · 3609 次点击
    这是一个创建于 114 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近有个需求,需要将 PostgreSQL 里的数据导出到 excel 里(或者 csv ),可能出现的情况有 3 种:

    • 1.导出单张表某个时间段的数据
    • 2.导出单张的全部数据
    • 3.导出所有表的全部数据(一张表一个文件存储)

    现在问题是如果导出的数据太大的话会 OOM,如何解决呢?

    现在想预估一个安全行数,在导出的行数达到安全行数后就保存这个 excel,然后再从数据库读取再追加到这个 excel 里。疑问是再次向这个文件里追加数据的时候这个文件里之前已有的数据会载到内存里来吗?

    有做过的前辈分享下经验吗?

    语言:go

    公司内部项目,所以用户量很少,基本上就几个人使用

    46 回复  |  直到 2019-08-16 16:51:24 +08:00
        1
    taotaodaddy   114 天前 via Android
    为什么不自己试试呢
        2
    myself659   114 天前
    有时间我可以将这个功能加上
    https://github.com/myself659/csvdata
    但是一般 csv 不会这么大
        3
    myself659   114 天前   ♥ 1
    对于大大 程序分片一下就可以了
    都那么大导出了一个 csv 中
    不存在这种需求
    反过来想一想都在一个文件里面,哪得用什么电脑才能打开 csv
        4
    wanganjun   114 天前 via iPhone   ♥ 1
    pg 有导出数据到 csv 的 sql 命令,还支持重定向数据到外部程序的功能,可以实现导出到压缩文件的功能
        5
    auser   114 天前   ♥ 2
    csv 有个 65535 限制的问题 .....

    这个问题应该是 Go 的内存管理与第三方解析库的问题。数据量太大的话,要自己从“底层”实现了。

    我这边处理的 xlsx 对应数据表量级在 30 万左右,几百兆的数据库文件。导出功能都是按日期筛选的,还没遇到要考虑内存的程度。

    建议直接花钱加内存解决,相比解决这个问题的工钱是小钱了。如果真到了加内存都解决不了的数据量,我觉得文件使用者也没有电脑能处理这么大的 excel 文件吧。
        6
    zjj2008se   114 天前 via Android   ♥ 1
    为什么不试试神奇的 pandas 呢?直接从数据库里面取出来存成你想要的各种格式
        7
    x2ve   114 天前
    哟哟切克闹 etl 来一套
        8
    hoyixi   114 天前   ♥ 1
    很多数据库,本身就支持把数据备份成 csv
        9
    littlewing   114 天前 via iPhone
    mysql 可以直接一条 sql 导出的
    话说你是 select * from table ?
        10
    imherer   114 天前
    @littlewing 嗯,因为是全字段都需要的。
        11
    liprais   114 天前   ♥ 1
    pgdump 之后再处理呗
    多读点文档没啥坏处
    或者你可以用 spark 开多个 jdbc 链接做导出
        12
    encro   114 天前   ♥ 2
    读数据,一次 10 万以内的读;
    写 csv,一行一行写;
    根本就不占用内存。
        13
    Kaiux   114 天前   ♥ 1
    https://github.com/alibaba/easyexcel
    阿里巴巴开源的, 虽然是 Java 做的,但是思路可以参考
    我本地导出 10 万数据都是 5 秒以内, 没有 OOM
    希望可以帮到你
        14
    wayne1027   114 天前
    @auser #5 csv 没有行数限制吧?哪来的 65535 ?几百年前的 xls?
        15
    maierhuang   114 天前
    copy 命令了解一下 就是不知道怎么和 go 结合
        16
    Michaelssss   114 天前
    1G 左右 CSV,excel 2016 就已经打不开了。。我不确定你说大量要多大。。。
        17
    SbloodyS   114 天前   ♥ 1
    copy 导出 csv,Excel 一个 sheet 最多 104W,按小于等于 104W 行的数量 分片处理为多个 sheet 就好
    追加数据就新开一个 sheet 来存
    之前试过 1 亿行数据十几分钟就好了,很快的,不过一般 Excel 10 个左右的满 sheet 打开就慢到爆炸了
        18
    imherer   114 天前
    @maierhuang 嗯,我也搜到了这个命令,直接写成 sql 语句在程序里执行就行,还挺好用的
        19
    augustheart   114 天前
    虽然我不懂 go,但是 csv 不就是文本?按文本处理你想怎么追加都行。
        20
    maierhuang   114 天前
    @imherer 那能用 copy 就完美解决
        21
    auser   114 天前
    @wayne1027

    文件格式本身不限制,但身边环境大家常用的 Numbers.app 不支持打开 65535 行的 csv.

    最麻烦的是这个格式在与 Windows 系统交换时经常遇到乱码问题。目前统一使用 xlsx.
        22
    imherer   114 天前
    @auser 对,我现在也遇到了,在 Mac 下导出 csv 中文正常,windows 下导出就乱码…… 头疼……
        23
    imherer   114 天前
    @maierhuang 嗯,但是好像不支持参数
    COPY (SELECT * FROM test LIMIT $1) to '/absolute path/file_name.csv' with csv header
    直接报错
        24
    auser   114 天前   ♥ 1
    @imherer

    哈哈,对于文本格式的文件,还有 BOM 这个可能出现的“小坏蛋”呢。

    几年前刚接触新团队的时候,现有成员全部用的 Windows 开发。Windows 的 git 有个换行符自动转换功能,可是很多人安装 git for windows 的时候一直下一步或者压根就不知道这个问题,加上 git 图形版客户端与编辑器各用各的,源码文件跟 git diff 没办法看。我还遇到一个项目内的某些源码文件竟然编码不唯一的神奇问题,很诡异,也很好奇怎么会出现这种情况。这个大型 C++项目在 VS 下有时候编译不过去,最后发现也是文件编码问题造成的。

    这是纯文本文件固有的问题。

    所以有统一的跨平台格式,优先选择它可能会少遇到些绊脚石。
        25
    Vegetable   114 天前   ♥ 1
    xls 65535,xlsx 大概是一百来万行,所以这两个基本就不考虑了,没等 oom 本身就已经装不了这么多数据了.
    只能是 csv.csv 可以 stream 进去,完全不存在 oom 的问题.
        26
    gamexg   114 天前   ♥ 1
    csv 格式省心, 打开文件一行一行的写,内存不会炸。

    没用过 [email protected],查了下也是支持 stream 的: https://github.com/go-pg/pg/issues/82
        27
    gamexg   114 天前
    @gamexg #26 确认了,lib/pg 也是默认就是游标方式工作,直接用 go 的 sql 标准库就可以处理大量数据。
        28
    mengdodo   114 天前
    pandas 就问你要多大
        29
    habicat   114 天前
    pandas+1
        30
    lmingzhi08   114 天前   ♥ 1
    感觉可以先将数据表 copy to 导出一个 csv 文件,csv 本身是一个文件文件,然后可以按行数切割文件了

    http://burnignorance.com/linux-tips-and-tricks/splitting-a-large-csv-files-into-smaller-files-in-ubuntu/

    To split large CSV (Comma-Separated Values) file into smaller files in Linux/Ubuntu use the split command and required arguments.

    split -d -l 10000 source.csv tempfile.part.

    Here “ 10000 ” indicates that each new file contains 10000 records,you change it to any number you want to, the smaller files would have that number of records. The new files are created with numbers suffixed. For example in this case the file names are tempfile.part.00.csv, tempfile.part.01.csv and so on.
        31
    changdy   114 天前
    我也在好奇 excel 用什么语言做导出比较合适.
    楼上有提到过 阿里巴巴的 开源项目.
    但是个人感觉从命名到来看 代码并不美观.并且封装的也不够完整.
    想问下 V2EX 的各位道友 用什么语言的那个项目比较合适?

    @imherer 友情提示 win offcie 默认是 gbk... 这方面都不如 wps.
        32
    abcbuzhiming   114 天前
    @Michaelssss excel 是存在最大行限制的。所以如果打算导出为 excel,无论是 xls 还是 xlsx 都得考虑最大行限制
        33
    danmu17   114 天前
    不出意外的话你的需求就是 pandas 典型的应用场景。
        34
    loading   113 天前 via Android
    先查总条数
    然后循环分批读写,每次一万行写一个 csv
    然后根据总天数得到你 csv 个数,你可以预设到一个 unix 时间戳建立的文件夹,叫 1.csv 2.csv

    最后是打压缩包下载还是 copy 拼起来就看你们了。
        35
    windedge   113 天前
    用 petl, 对文本文件(csv), petl 内存占用很低, 写法也很简单:

    ```
    import petl as etl
    import psycopg2
    connection = psycopg2.connect('dbname=example user=postgres')
    table = etl.fromdb(connection, 'SELECT * FROM example')
    etl.tocsv(table1, 'example.csv')
    ```
        36
    IamNotShady   113 天前
    写到文件就行了 分批次写
        37
    Mithril   113 天前
    写大文件可以 File Mapping,很容易。
    但是不建议做成 CSV,这东西不是一个非常标准的规范,总有各种各样的问题。
    如果你导出的数据只是内部使用,可以直接导出到 Sqlite 或者 Access 数据库。
    这种的 Excel 也能直接用
        38
    sonyxperia   113 天前
    直接用 dump 嘛
        39
    wqzjk393   113 天前
    先考虑下你是不是真的需要这么多数据这么多字段,保存成 excel csv 以后无论用什么工具打开都会非常慢,保存下来真的能用到么?
        40
    maierhuang   113 天前
    @imherer 那直接在外面拼接好了 sql 再执行
        41
    jalena   113 天前
    不是又个命令是 copy 嘛,可以直接输出到文件
        42
    cmonkey   113 天前
    是时候让公司那几个人学习 PostgreSQL 了,给他们开 read 权限
        43
    imherer   113 天前
    @cmonkey 😂😅
        44
    imherer   113 天前
    @jalena 嗯,目前就是这样实现的
        45
    yogogo   113 天前
    先导出到服务器,再把文件下载
        46
    shangfabao   113 天前
    用 postgresql 自带命令执行不好么??
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   955 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 27ms · UTC 19:29 · PVG 03:29 · LAX 11:29 · JFK 14:29
    ♥ Do have faith in what you're doing.