Excel操作工具(Easyexcel vs EEC)对比(三)

点击这里查看原文

从BIFF8开始Office就使用SharedString方式保存字符串,使用共享字符串可以达到压缩文件的目的,但是POI使用的是inlineStr方式写字符串,easyexcel底层是POI所以自然的继承了这一方式,EEC默认也是使用inlineStr方式,可以使用注解@ExcelColumn(share = true)来使用SharedString方式。

上一篇我们对比了easyexcel和EEC两款工具在inlineStr模式下读写Excel文件的性能和内存,本文是对比系列的最后一篇,主要对比两款工具在SharedString模式下的读写性能以及Excel 97~2003格式读取性能。由于easyexcel不支持SharedString模式、EEC不支持xls格式写文件,所以本文只对比两个工具的读性能。

测试实体与上篇基本一致,只是添加了省/市/区3列文本,这3列值大概率重复(毕竟我国的省/市/区数据是确定的,有限的),所有字符串均添加注解@ExcelColumn(share = true)强制使用SharedString模式。
具体测试细节可以查看上一篇,测试代码在这里eec-poi-compares

测试文件内容如下

1. 测试机器配置

硬件:

  • CPU: 3 GHz Intel Core i5 (6核)
  • 内存: 16 GB 3000 MHz DDR4
  • 硬盘: Samsung SSD 970 PRO 512GB(267G可用)
  • 系统: macOS 10.14.4

测试版本:

  • easyexcel: 2.1.6
  • EEC: 0.4.6
  • EEC-E3-SUPPORT 0.4.6

2. xlsx格式读写

2.1. 64MB内存

限制内存64MB测试

先跑一个1w~100w的读写

描述 1w 5w 10w 50w 100w
EEC(Write) 0.586 2.738 5.394 26.380 58.51
EEC(Read) 0.349 1.716 3.242 15.209 30.664
Easy excel(Read) 1.109 5.468 11.35 55.55 112.187
倍数 318% 319% 350% 365% 366%

CPU截图鼠标左边为EEC,右边为Easyexcel

64MBCPU测试截图

内存截图鼠标左边为EEC,右边为Easyexcel

64MB内存测试截图

与inlineStr模式相比两者速度差距有所拉大,EEC的读取速度超过easyexcel2倍

2.2. 32MB内存

限制内存32MB测试

从这里开始以下所有测试均只测试文件读取

描述 1w 5w 10w 50w 100w
EEC 0.399 1.728 3.227 15.667 32.14
Easy excel 4.716 34.662 63.444 296.302 656.734
倍数 1182% 2006% 1966% 1891% 2043%

CPU截图鼠标左边为EEC,右边为Easyexcel

32MBCPU测试截图

内存截图鼠标左边为EEC,右边为Easyexcel

32MB内存测试截图

在32MB限制下easyexcel内存一直处于满载状态,且GC占用CPU很高,速度仅为EEC的1/10〜1/20。

2.3. 探底EEC最低使用内存

经多次测试我最终运行在10MB处完成1~100w测试,测试过程中我发现数据量并不能直接影响内存。

描述 1w 5w 10w 50w 100w
EEC读 0.391 1.887 3.695 16.965 34.719

CPU波动


10M_CPU

内存波动


10M_内存

Easyexcel在10MB下抛OOM错误,

com.alibaba.excel.exception.ExcelAnalysisException: java.lang.OutOfMemoryError: GC overhead limit exceeded

    at com.alibaba.excel.analysis.ExcelAnalyserImpl.analysis(ExcelAnalyserImpl.java:122)
    at com.alibaba.excel.ExcelReader.readAll(ExcelReader.java:160)
    at com.alibaba.excel.read.builder.ExcelReaderBuilder.doReadAll(ExcelReaderBuilder.java:275)
    ...
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3406)
    at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3226)
    at java.io.ObjectInputStream.readString(ObjectInputStream.java:1905)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1564)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)

3. xls格式读写

测试内容与上面完全一样,测试文件首先由EEC生成xlsx格式,然后再转为xls格式,代码如下

private void eecWritePaging(final String name, final int loop) throws IOException {
    new Workbook().addSheet(new ListSheet<LargeSharedData>() {
        int n = 0;
        @Override
        public List<LargeSharedData> more() {
            return n++ < loop ? createSharedData() : null;
        }
    }).setWorkbookWriter(new XMLWorkbookWriter() {
        @Override
        protected IWorksheetWriter getWorksheetWriter(Sheet sheet) {
            return new XMLWorksheetWriter(sheet) {
                /**
                 * xls每个Worksheet最大包含65536行x256列,所以这里设置分页
                 * 参数为{@code 65536-1}(去除第一行的表头)
                 * 
                 * @return 每页最大行限制
                 */
                @Override
                public int getRowLimit() {
                    return (1 << 16) - 1;
                }
            };
        }
    }).writeTo(defaultTestPath.resolve(name + ".xlsx"));
}

最终的测试文件如下:

File Size
eec shared 1w.xls 6.9M
eec shared 1w.xlsx 1.8M
eec shared 5w.xls 35M
eec shared 5w.xlsx 9.1M
eec shared 10w.xls 71M
eec shared 10w.xlsx 18M
eec shared 50w.xls 487M
eec shared 50w.xlsx 92M
eec shared 100w.xls 978M
eec shared 100w.xlsx 185M

进入主题开始测试吧

3.1 64MB内存

先跑一波64MB内存限制下1~100w的读操作

描述 1w 5w 10w 50w 100w
EEC 0.198 0.603 2.779 7.463 15.627
Easy excel 1.138 - - - -
倍数 575% - - - -

如上图,在64MB内存限制下,easyexcel只能完成1w数据的读测试,EEC则可以完成1〜100w的读测试。

easyexcel具体的报错信息

org.apache.poi.util.RecordFormatException: Unable to construct record instance

    at org.apache.poi.hssf.record.RecordFactory$ReflectionConstructorRecordCreator.create(RecordFactory.java:98)
    at org.apache.poi.hssf.record.RecordFactory.createSingleRecord(RecordFactory.java:345)
    at org.apache.poi.hssf.record.RecordFactoryInputStream.readNextRecord(RecordFactoryInputStream.java:289)
    at org.apache.poi.hssf.record.RecordFactoryInputStream.nextRecord(RecordFactoryInputStream.java:255)
    at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.genericProcessEvents(HSSFEventFactory.java:175)
    at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processEvents(HSSFEventFactory.java:136)
    at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:82)
    at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:54)
    at com.alibaba.excel.analysis.v03.XlsSaxAnalyser.execute(XlsSaxAnalyser.java:112)
    at com.alibaba.excel.analysis.ExcelAnalyserImpl.analysis(ExcelAnalyserImpl.java:105)
    at com.alibaba.excel.ExcelReader.readAll(ExcelReader.java:160)
    at com.alibaba.excel.read.builder.ExcelReaderBuilder.doReadAll(ExcelReaderBuilder.java:275)
  ...
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.String.<init>(String.java:166)
    at org.apache.poi.hssf.record.RecordInputStream.readStringCommon(RecordInputStream.java:405)
    at org.apache.poi.hssf.record.RecordInputStream.readUnicodeLEString(RecordInputStream.java:376)
    at org.apache.poi.hssf.record.common.UnicodeString.<init>(UnicodeString.java:464)
    at org.apache.poi.hssf.record.SSTDeserializer.manufactureStrings(SSTDeserializer.java:57)
    at org.apache.poi.hssf.record.SSTRecord.<init>(SSTRecord.java:252)

从错误信息上发现在解析SSTRecord时抛OOM错误。SST即Shared String Table的简称,大概率是POI将SST中的字符串全部拉到内存导致OOM。SharedStringTable在EEC中的处理一文中有详细介绍SST在POI中的实现,感兴趣的朋友可以移步去了解一下。

3.2 10MB内存

10MB限制下easyexcel全军覆没,错误同上。

描述 1w 5w 10w 50w 100w
EEC 0.199 0.763 1.737 9.224 18.537

内存截图:


3.3 不限制内存

由于easyexcel未完成上面的测试,所以我决定放开限制再分别跑一次

描述 1w 5w 10w 50w 100w
EEC 0.151 0.453 1.109 6.651 13.880
Easy excel 0.628 2.810 4.55 32.116 118.69
倍数 416% 620% 410% 483% 855%

对于xls格式的读取速度EEC远超Easyexcel,附两者测试CPU和内存截图,上面为easyexcel下面为EEC,不限制内存的情况下,前者最大分配7G堆内存,最大使用堆4.7G。EEC最大分配700MB,最大使用350MB。


CPU & RAM

我还发现一个有趣的现象,无论是EEC还是Easy excel,xls格式读取时间远小于xlsx

极限内存测试

在读取xls格式中,我分别对EEC和Easyexcel进行了极限内存测试,也就是跑完测试不抛异常时的最小内存,结果如下。

描述 1w 5w 10w 50w 100w
EEC 3M 3M 3M 5M 7M
Easy excel 50M 220M 440M 2400M 5000M

从上图可以看出随着文件逐渐增大easyexcel所需内存也逐渐增大,读取文件所需的内存甚至远远超过文件本身的大小,而EEC读文件所需内存一直比较平稳且远低于easyexcel,基本可以在10MB下完成大文件读取。

总结

通过前面的测试,我们对两款工具的便利性和性能有了一定的了解,与POI或easyexcel相比,EEC有着更新的设计理念,天然支持Worksheet分页、数据分片、支持高亮、支持流式读取、延迟读取等一些提高生产力的特性,且拥有更简洁、优雅的API也降低了接入成本。无论在速度优化还是内存控制方面EEC都远优于POI,毕竟POI是十几年前的产物,就算easyexcel在此基础上有极大改善但是与EEC相比还有一定差距,可以说EEC是目前所能找到的同类产品使用内存最小的工具,没有之一!!!

虽然EEC不支持xls的写入但瑕不掩瑜,尤其是微软已经停更xls格式多年,不支持xls格式写入也不会有太多功能损失。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351