问题描述
一个Request里面一般会多次访问数据库吗?如果业务稍微复杂一点的话,比如,要取的数据很多。现在有一下场景,根据一个accountId,会查询出很多的clientId,然后对每个clientId进行统计(比如sum,avg。。。group by)。这样就导致我一条SQL 语句不满足需求;我现在是这样做的,先根据accountId查出需要的clientIds,然后循环每个clientid,对每一个clientid,再去数据库查询统计相关的数据。我还有第二种想法,先把所有的数据都取出来,然后自己再进行一些统计,统计这一块用java代码去实现。不知道一般做法是怎么样的?欢迎指教。 问题补充:SELECT A.* FROM (SELECT F84PLANID, F81COLDAT, SUM(F84DEALAMT) R1FROM D03PRO/F81, D03PRO/F84WHERE F81COLLID = F84COLLID AND F81MCID = '000036' AND F84MCID = '000036' AND F84PLANID IN ('0000022289', '0000025222', '0000025554', '0000022346') AND F84CANCYN = 'N'GROUP BY F81COLLID, F81COLDAT, F84PLANIDORDER BY F84PLANID, F81COLDAT DESC) A , (SELECT B.F84PLANID, MAX(B.F81COLDAT) R2 FROM (SELECT F84PLANID, F81COLDAT, SUM(F84DEALAMT) R1FROM D03PRO/F81, D03PRO/F84WHERE F81COLLID = F84COLLID AND F81MCID = '000036' AND F84MCID = '000036' AND F84PLANID IN ('0000022289', '0000025222', '0000025554', '0000022346') AND F84CANCYN = 'N'GROUP BY F81COLLID, F81COLDAT,F84PLANIDORDER BY F84PLANID, F81COLDAT DESC ) BGROUP BY B.F84PLANID ) CWHERE A.F84PLANID = C.F84PLANID AND A.F81COLDAT = C.R2ORDER BY A.F84PLANID这条SQL的效率如何。。。总感觉挺怪的。。。在DB2环境下,执行下要2秒。。。
解决方案
你可以用sql子查询来完成,应该可以满足你说的需求。如果通过sql子查询无法满足的话,可以分多次去访问数据库,没有问题的。最好不要自己用java代码去实现,这样不但效率底,而且还增加了代码的复杂度。最好的原则是:1.首先考虑用一个sql去实现,除非因为复杂的sql文,导致执行效率低。2.如果一个sql无法实现,或者执行效率太低,可以写成多个sql文,分多次去访问数据库3.当然如果用java实现比较简单的话,也可以考虑,因为这样可以降低数据库的负载。
解决方案二:
我觉得像这种取大量数据的统计数据比较好的办法就是后台定时先将需求的数据统计好放到静态表里,前台直接取这个表里的数据就行了。不过牺牲了实时性!如果数据量不是很大,实时统计数据的时间能在接受范围内可考虑写存储过程直接调用; 你说的两种做法如果数据量很小的情况下都是可选的,但是数据量大就不要考虑了!
解决方案三:
中庸一下:多次访问+分页查询(一次可以得到多条数据):优点:减少了数据库访问次数,又得一次得到多条数据
解决方案四:
sum,avg。。。group by,可以做成一个一个的视图,然后用sql直接全部调用,一次性去取出来,但是这样的话,数据库的压力会大一点.
解决方案五:
从数据库里读数据,如果可以的话,尽可能一次就把数据读出来。这是一种好习惯。不管有没有连接池的存在。
解决方案六:
因为有数据库连接池的存在,多次访问开销没有想想的那么大对于你的第一想法,目前来看是可以根据一条 SQL 统计出的,囧...或者可以在数据库里建立一个视图,简化 SQL .第二个想法,不推荐,原因1: 那这样还不如直接在内存里缓存了,何必一次次的读.原因2: 基于原因1,太吃内存....而且又要维护内存里的数据和数据库中的数据,代码复杂了.
解决方案七:
(1)如果Request频率不高的话可以考虑使用sql或者java代码去实时统计;(2)但如果访问频率较高的话,最好就采用后台服务进行单独统计后写入静态表,访问时直接读取静态表(@zw的回答)