功夫都在报表外-漫谈报表性能优化

2023-12-12 02:38

本文主要是介绍功夫都在报表外-漫谈报表性能优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第3期:封面图片

应用系统中的报表,作为面向业务用户的窗口,其性能一直被高度关注。用户输入参数后都希望立即就能看到统计查询结果,等个十几二十秒还能接受,等到三五分钟的用户体验就非常恶劣了。

那么,报表为什么会慢,又应当从哪里入手进行性能调优呢?

数据准备

当前应用中的报表大都用报表工具开发,当报表响应太慢时,不明就里的用户就会把矛头指向使用报表工具的开发人员或者报表工具厂商。其实,大多数情况报表的慢只是个表现,背后的原因是数据准备太慢,在数据进入报表环节之前就已经慢了,这时再去优化报表开发或压迫报表工具并没有用处。

报表是给人看的,人类视力限制不可能查看过多数据,也就没有大数据的呈现需求。报表工具为了直观而采用的状态式计算模型,也不适合实现有复杂过程的计算。报表环节不应当也无能力解决大数据和复杂计算问题,只要处理小数据的摆位和简单计算,这不会耗用太多时间。

八成左右的报表慢是因为数据准备造成的。报表呈现的数据量虽然小,但涉及的原始数据量可能巨大,把大数据汇总和过滤成小数据需要很长时间;复杂计算也是类似,主要时间消耗在数据准备阶段。数据准备的优化是报表提速的关键。

1. 优化数据准备代码:一般是SQL(或存储过程),某些时候是应用程序的代码(涉及非数据库或多数据库时);

2. 数据库扩容:数据量大,代码不能再优化时,还可以扩容数据库,比如采用集群方案;

3. 采用高性能计算引擎:传统数据库在实现某些运算时性能较差或成本太高,可以更换为其它计算机制;

数据计算

报表环节本身计算性能差的情况相对少,但也是有的。

一个典型的场景是多源关联报表,即把多个二维数据集按某个主键对齐呈现,有时可能还需要分组汇总。报表工具要求把计算都写进单元格,这样只能用数据集过滤来描述本格和其它数据集的关联,类似ds2.select(ID==ds1.ID)的表达式。这个运算复杂度是平方级的,在数据量不大时也无所谓,但数据量稍大(几千行)且涉及数据集较多时,性能就会急剧下降,从几秒到几十分钟都有可能。

如果我们把这个运算移到报表外,在数据准备阶段时处理,就可以大幅度提升性能。如果数据来自同一个数据库,那么用SQL写JOIN语句就可以了,如果数据集来自多库或者希望减轻数据库计算压力,也可以在外部实现HASH JOIN算法。HASH JOIN算法可以整体地看待几个数据集,效率比报表工具采用的过滤式关联要高得多,几千行规模时几乎是零等待。

报表计算性能差虽然发生在报表环节本身,但经常却要在报表外去解决。

其它类似场景还有,如带部分明细行的分组汇总表,表现出来是由于报表环节处理数据量大导致运算变慢,而解决方法也是把运算移到报表外。

数据传输

报表还有个慢的瓶颈在于数据传输。

目前很多应用都是J2EE架构的,采用的报表工具也是Java写的,这时访问数据库都要用JDBC接口。然而,某些常用数据库的JDBC驱动性能很差(这里就不点名了),取出数据量稍多(几万行)时就会有明显的等待感。这就导致一个无奈的现象:数据库压力很轻计算很快,报表端计算也不算复杂,但报表仍然很慢。

无论应用开发商还是报表工具厂商都没办法改变数据库的JDBC驱动,只能在外面想办法。经过多次实验,我们发现启用多线程并行取数就能获得数倍的性能(前提是数据库负担轻)。但是,目前还没有报表工具直接提供了并行取数的功能(由于数据分段方法和数据库及取数语法相关,需要代码控制,也不容易做成报表功能),这个方案仍然要在报表环节外的数据准备阶段来实施。

可控缓存

把近期访问过的报表缓存起来,短时间内再次访问同参数的报表时可以不必计算而直接返回,显然这能改善用户体验。很多报表工具也都提供有缓存功能,不过并不细致,缓存只能针对整个报表,而且各个报表的缓存是无关的。在报表外下点功夫可以实现控制力度更细致的缓存功能:

1. 部分缓存。有些报表、特别是常见的多源报表,其中大部分数据相对稳定(历史数据),只有小部分数据时效性差(当期数据)。而整个报表的缓存的有效期只能以较短的为准,这样会导致报表经常被重算。如果能只缓存部分数据,就能延长这部分缓存的生命期,从而减少计算量。

2. 缓存复用。不同的报表可能引用到同样的数据,而互相无关的报表缓存机制则会迫使这些报表多次重复计算同样的数据。如果能让某个报表引用到其它报表已经计算出来的缓存数据,也能有效减少计算量。

这些复杂的缓存控制需要编写代码来实现,不容易在报表工具中提供,但在可编程的数据准备阶段实施却相对容易。

清单列表

前面说过,报表和大数据的直接关系并不大。甚至可以说老是喊大数据报表的厂商多半是忽悠。

不过有一种清单列表确实是大数据报表。清单列表在金融行业经常碰到,把一段时间的交易清单列出来。其特点是数据量特别大,可能会有几千上万页,不过计算会相对简单,经常只是罗列,最多有些按页按组的汇总。

报表工具为了处理灵活的格间运算,一般都会采用全内存方式。这样,把清单列表加载进报表工具时,会大概率出现内存溢出;而且太大数据量全部取出并加载也需要很长时间,用户难以容忍。

容易想到的办法是边读取边呈现,每次只呈现一页,不会溢出;读满一页后立即呈现,用户不会有太强的等待感。数据库都提供有游标可以逐步读出数据,但用户可能在前端翻页,这还需要高速随机按页(行)取数的能力。数据库就没有这种接口了,用条件过滤取数不仅很慢,而且还由于数据可能仍在更新而不能保证报表在生命周期内的数据一致性。

结果还是要在数据准备阶段解决。两个异步线程:一个负责从数据库取数并缓存到外存(假定数据量大内存装不下),另一个接受前端请求从缓存中按页(行)取出数据返回。

这篇关于功夫都在报表外-漫谈报表性能优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/482943

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

MySQL中my.ini文件的基础配置和优化配置方式

《MySQL中my.ini文件的基础配置和优化配置方式》文章讨论了数据库异步同步的优化思路,包括三个主要方面:幂等性、时序和延迟,作者还分享了MySQL配置文件的优化经验,并鼓励读者提供支持... 目录mysql my.ini文件的配置和优化配置优化思路MySQL配置文件优化总结MySQL my.ini文件

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题