开始
我们公司支持的一种会计和报告系统的存储量开始迅速增长。 该系统使用Yii2框架以PHP编写。 最初,报告是通过PhpSpreadsheet库构建的,该库取代了长期使用的PhpExcel。
在不同类型的报告中,有一个非常大-实际上,应将存储在数据库中的所有数据的完整集合上载到一个excel表中。 在最初阶段,没有问题,但是当卷的数量开始超过数十万条记录时,卸载编排脚本在超时限制时开始下降。
首先,我们提高了此限制,并开始寻找解决问题的方法。 但是临时解决方案并没有持续很长时间-时间限制的问题变成了内存限制的问题。 他们将“ RAM”扔给服务器,并删除了此特定操作的memory_limit。 很快,用户开始再次抱怨运行时错误。 我必须删除完整报告的时间限制。 但是,坐在屏幕上观看带有加载指示器的十几分钟并没有什么乐趣。 此外,有时“现在和现在”都需要一份报告,事实证明,花在形成报告上的每一分钟都是至关重要的。 停止了使用环境设置的实验,划伤了脑后,开始优化代码。
寻找解决方案
完成的第一件事是将报告脚本放置在后台进程中,并且用户通过“进度栏”监视进度。 通过使用Redis进行存储的队列机制来实现后台作业执行。 系统中的工作不会停止,您可以执行其他任务并定期返回报告页面以查看文件是否准备就绪。 文件形成后,立即为用户提供下载链接。 但是,如上所述,有时“立即”需要该文件,而增加可用性并不能解决该问题。 同时,数据量持续增长,构建文件所需的时间达到了79分钟! 这是完全不能接受的,尤其是考虑到报告是该系统功能的基础之一。 不,所有其他部件的工作原理都像发条一样,但是这种美中不足的地方破坏了整体印象。
初步结果
我们再次坐下来进行代码分析。 测试的第一件事是从数据库中选择数据的过程。 但是查询已经以最大可能的方式进行了优化。 尽管最长的请求是一个可怕的示例,其中有五个或六个调用了可怕的FIAS,但它在2到5秒内就解决了。 弱点不是他,而是文件“ exelnik”的形成。 已经开始尝试优化此过程。 从在redis中缓存开始,到变态,例如在并行流中形成单独的小“ excel”,然后粘贴到一个文件中。 但是结果始终是相同的:随着时间的流逝,问题变成了内存问题,反之亦然。 没有中间立场,只有从一个极端流向另一个极端。 经过一定数量的数据后,该库的资源消耗开始呈指数增长,并且无法击败它。 PhpSpreadsheet-不适合大文件。 结果,决定更改该库。 作为一种选择-编写自己的模拟文件以形成ex文件。
分析和工具选择
他们并不想着急写自行车,但首先,他们分析了现有的解决方案。 在可能的选项中,仅盒子/壶嘴是令人感兴趣的。 使用该库快速重写模块。 结果,在145秒内获得了完整的报告。 让我提醒您,PhpSpreadsheet的最新测试是79分钟,而这里是2.5分钟! 进行测试:将数据量增加2倍。 该报告在172秒内生成。 区别是惊人的。 当然,该库不具有与PhpSpreadsheet相同的功能,但是在这种情况下,由于速度至关重要,因此最少的工具集就足够了。
Yii2的扩展
最终决定是对Yii2的扩展。 也许有人会派上用场。 该扩展允许您将任何数据集从GridView上传到excel,同时保持过滤和排序。 它使用yii / queue和box / spout作为依赖项。 使用扩展名来形成真正的大文件是很有意义的,至少要有50,000行=)目前,已成为扩展名基础的模块可以应付近600,000行的负载。
链接到github:
Yii2 ExcelReport Extension感谢您的关注!