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

想起几年前刚毕业有一道面试题。

  •  
  •   frank1256 · 2022-09-17 11:06:30 +08:00 · 4211 次点击
    这是一个创建于 796 天前的主题,其中的信息可能已经有所发展或是发生改变。

    语言限制 Java 吧,内存 4g 。

    效率最高 从 Msql 里读取 50W 条数据,写入 execl 的方法。

    现在想想这个题目,我给的答案是游标读取 mysql ,randomAccess 或者 nio 写入 execl ?各位大佬指点指点,感觉好像怪怪的。

    15 条回复    2022-09-19 08:53:58 +08:00
    misaka19000
        1
    misaka19000  
       2022-09-17 11:44:58 +08:00
    一条数据多大
    wangyiyi10
        2
    wangyiyi10  
       2022-09-17 11:56:12 +08:00
    感觉应该是顺序写 csv 文件吧? EXCEL 可以打开是不是就满足写入 excel 了。
    makdon
        3
    makdon  
       2022-09-17 12:25:23 +08:00
    读 mysql 可以并行分页拉,这样瓶颈在网络带宽 /MySQL 性能
    写文件如果是 xlsx 的话可能比较慢,如果是 csv ,用 mmap 写应该会快一点?
    题目信息有点少,应该是展开聊的开放题吧
    VensonEEE
        4
    VensonEEE  
       2022-09-17 14:37:09 +08:00
    各位大佬,50W 很多么?能写 excel 的,估计也没有大字段吧,4G 内存还不够?
    az467
        5
    az467  
       2022-09-17 16:01:31 +08:00
    多线程提效率,减少 CPU 浪费,流式处理防止 OOM 。

    不过五十万这数据量也太小了。
    mylifcc
        6
    mylifcc  
       2022-09-17 16:05:38 +08:00
    其实就是考一个数据几 k 一次读满 4g 多少条 这种思维 感觉没啥卵用
    berg223
        7
    berg223  
       2022-09-17 18:17:43 +08:00   ❤️ 2
    假设一行数据有 50 个字段,每个字段 8 字节,一行占用 50*8=400B ,大约 2.5 分之一 KB ,50w 除以 2.5 大概 200MB ,数据量不算大,4g 内存大概是这个规模的 20 倍,不算大的,也就是说每个字段 8 字节,1000 个字段才会在内存上有瓶颈。瓶颈是在 io 上,假设数据是写到同一块机械硬盘上,仅考虑性能的话,在写的时候实际上都不需要并发和 nio 啥的,直接拼接成一个 csv 格式的字符串往硬盘上怼,最大化利用磁盘顺序写的特性,这样速度理论上应该最快。但是实际工作中考虑扩展性不应该这么干。事实上这块的 io 应该是 ms 级别的。
    假设要读取的 mysql 数据是同一块硬盘,多线程也不一定比单线程快,因为瓶颈在于 io 上,读取的 io 分两类,一个是程序和 mysql 之间的网络连接,另一个是 mysql 读取磁盘的 io 。对于第二类肯定单线程比多线程快,对于第一类来说多连接应该比单连接要快,假设机房带宽是 100Mbps=12.5MB ,那么单连接传输 200MB 数据大概需要 200/12.5=16 秒,假设磁盘速度是 100MB/s 的话,单次读取所有数据就只需要 200/100=2 秒,加在一起就是 18 秒,开 x 个连接读取等量数据大概需要 16+2/x 秒,优化空间是秒级别的,最大优化空间不超过 2s ,当然不是 x 越大越好。
    综上,这题最多优化 2s ,未优化前速度大概是 20s 左右,确实没多大优化空间。
    berg223
        8
    berg223  
       2022-09-17 18:18:45 +08:00
    @berg223 更正下,事实上这块的 io 应该是 ms 级别的更正为 “事实上这块的 io 的优化空间应该是 ms 级别的”。
    berg223
        9
    berg223  
       2022-09-17 18:51:21 +08:00
    @berg223 回头看了下直接拼接成字符串往磁盘上怼应该是有问题的,需要把 jvm 的常量池设置大一些。。
    berg223
        10
    berg223  
       2022-09-17 18:56:39 +08:00
    @berg223 还是不对,字符串常量是在堆中的,只有字面量才会在常量池中,所以应该注意的不应该是常量池的大小。
    noparking188
        11
    noparking188  
       2022-09-17 22:09:17 +08:00
    @berg223 #7 老哥解答的很棒
    我 Java 不熟悉,不过稍微熟悉一点 Spark ,Spark 读 JDBC 的时候有一些参数设置提供范围分区并发读取,不过需要一个数字类型主键。对于文件 IO ,这个也许可以参考 Kafka 写优化的特点
    reeco
        12
    reeco  
       2022-09-18 00:10:28 +08:00 via iPhone
    这有啥难的
    nuk
        13
    nuk  
       2022-09-18 23:22:39 +08:00
    excel 写的时候有缓存,xml 构造不会慢,所以瓶颈是 mysql 读,而多线程读 mysql 肯定是更快的,所以这其实就是 MPSC 的问题。
    YepTen
        14
    YepTen  
       2022-09-19 08:48:55 +08:00
    我怎么感觉面试官是在问怎么把数据库数据写成 Excel 文件。其他语言不知道,但 java 写 Excel 之前是 POI ,这玩意可耗内存啊,之后是用阿里的 EasyExcel 。50W 的数据对数据库来说不是毛毛雨,直接读就是了。问题应该是在如何写,而不是读。
    YepTen
        15
    YepTen  
       2022-09-19 08:53:58 +08:00
    如果现在问这个问题,限定 Java 的话,就是直接读+EasyExcel 。一个方法里就写完了,我写过 100 万的数据到 Excel 表里,一点问题没有。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   969 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 21:43 · PVG 05:43 · LAX 13:43 · JFK 16:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.