报表项目总结

这个项目做的很累,主要参与做IS报表中正向批注指标。

工作量包括:

1. UI部分

IS报表页面中添加正向批注一列,正向批注明细的下钻页面

2. Java逻辑

Dao及 Service的实现

3. SQL

主要包括正向指标历史数据(存储过程生成的数据表 tst_in_postil)及实时数据(cust_in_postil)的查询SQL

由于需要统计正向批注的数量、正向批注明细的数量及展示正向批注的明细,故总共有三条SQL,最开始写出来的SQL效率很低,PM取消了实时查询的需求,故工作难点在于历史数据查询的SQL。

正向批注指标描述:

在查询时间范围内,商机有提升的客户跟进批注。如一条客户资料,在查询时间范围内,商机由0-20-0,则不算一条正向商机;若0-20-40-80-40,则算一条正向批注,且明细显示0-20、20-40、40-80的批注明细;

最开始的SQL思路:

1. 查询明细

I 遍历整表tst_in_postil,表按 add_time 做order by,然后按 cust_id, in_ucid做 group by, 这样找出查询时间范围内,对于一个cust,其In跟进的最早时间添加的商机 biz_before;

II  类似这样找出对于一个cust,其In跟进的最近时间添加的商机 biz_after;

III 找出所有满足正向批注的 cust_id, in_ucid;

IV 遍历整表,查询时间范围内,与上面的 cust_id, in_ucid相同的且商机有提升的明细;

对应SQL

SELECT DISTINCT temp1.cust_id, temp1.cust_name, temp1.in_realname, temp1.biz_before, temp1.biz_after, temp1.add_time

FROM tst_in_postil_daily  temp1  INNER JOIN  (

SELECT temp2.cust_id, temp2.in_ucid, temp2.biz_before, temp3.biz_after

FROM (SELECT cust_id, in_ucid, biz_before FROM (SELECT * FROM tst_in_postil_daily WHERE add_time > '2010-11-01' AND add_time < '2010-12-01'

ORDER BY add_time ASC) temp GROUP BY cust_id, in_ucid) temp2

INNER JOIN

(SELECT cust_id, in_ucid, biz_after FROM (SELECT * FROM tst_in_postil_daily WHERE add_time > '2010-11-01' AND add_time < '2010-12-01'

ORDER BY add_time DESC) temp GROUP BY cust_id, in_ucid) temp3

WHERE temp2.cust_id = temp3.cust_id AND temp2.in_ucid = temp3.in_ucid AND IFNULL(temp3.biz_after, 0) > IFNULL(temp2.biz_before, 0))  temp4

ON temp1.cust_id = temp4.cust_id AND temp1.in_ucid = temp4.in_ucid

WHERE temp1.add_time > '2010-11-01' AND temp1.add_time < '2010-12-01' AND IFNULL(temp1.biz_after, 0) > IFNULL(temp1.biz_before, 0)

2. 查询正向批注数

同上面思路,找到满足条件的所有正向批注的cust_id, in_ucid, count(*)

3. 查询正向批注明细数(用于分页)

同查询明细,只不过 select 的不是明细,而是 count(*)数数;

缺陷:

多次查询整表,整表几十W的数据量量,而且步骤3, 4需要做大表的Join查询,很费时间,查询的半年的数据(正向批注约6W行记录),需要跑二十多分钟,效率太低

优化1

取消所有的 inner join 改用自然连接来做,因为还是要做大表的连接查询,还是很慢,没有多大的改善。

优化2

I 合并步骤I,II, 因为做过一次 group by之后就可以统计出对应一个cust,其In添加批注的最早时间及最近时间;

II 据此时间查询出对应的商机,保存所有满足正向批注的cust_id, in_ucid;

III遍历整表,查询商机有提升的正向批注明细

缺陷:

其实效率低下的 join主要在于查询得到的满足 正向批注 的 cust_id,in_ucid集合和整表的Join,而这部分优化并没有改变这以现状,故实际效率仍然低下,虽有所提升,但没有太大改善。

对应的SQL

SELECT t1.cust_id, t1.cust_name, t1.in_employee_no, t1.in_realname, t1.biz_before, t1.biz_after, t1.postil, t1.add_time

FROM

(SELECT * FROM (

SELECT t3.*,

(SELECT t.biz_after FROM tst_in_postil_daily t WHERE t.cust_id = t3.cust_id AND t.in_ucid = t3.in_ucid AND t.add_time = t3.last1) AS last_biz,

(SELECT t.biz_before FROM tst_in_postil_daily t WHERE t.cust_id = t3.cust_id AND t.in_ucid = t3.in_ucid AND t.add_time = t3.first1) AS first_biz

FROM (

SELECT *, MAX(add_time) AS last1, MIN(add_time) AS first1 FROM tst_in_postil_daily

WHERE add_time >= '2010-11-01' AND add_time < '2010-12-01'

AND in_ucid IN (1968605, 1968615)

GROUP BY cust_id, in_ucid ) t3

) t2

WHERE IFNULL(t2.biz_after, '0%') > IFNULL(t2.biz_before, '0%') )  t5,

tst_in_postil_daily  t1

WHERE t1.cust_id = t5.cust_id AND t1.in_ucid = t5.in_ucid 

AND t1.add_time >= '2010-11-01' AND t1.add_time < '2010-12-01' AND IFNULL(t1.biz_after, '0%') > IFNULL(t1.biz_before, '0%');

优化3

其实对整表扫描一遍后,所有的信息都已经具备,很多 Join 操作都不是必须的。该优化主要在于在一次 group by 后就拿到满足正向批注的 cust_id, in_ucid及其商机有替身的批注明细数;对于分页查询放到Java逻辑中去处理,不作大表的Join,这样统计正向批注数及明细数、明细展示都不需要做大表join了,大大提升了大数据量的查询速度;

统计正向批注数

SELECT count(*) as totalCount

FROM (

SELECT cust_id, in_ucid,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_after, '0%') ORDER BY in_postil_id), ',', -1) AS last_biz,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_before, '0%') ORDER BY in_postil_id), ',', 1)  AS first_biz,

FROM tst_in_postil_daily

WHERE add_time>=? AND add_time<?  AND in_ucid = ?

GROUP BY cust_id, in_ucid HAVING IFNULL(last_biz, '0%') > IFNULL(first_biz, '0%')

) t1

备注:

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_after, '0%') ORDER BY in_postil_id), ',', -1)

其中GROUP_CONCAT函数用来把按 cust_id, in_ucid分组后的 biz_after 的数据以字符串的形式连接在一起,然后通过SUBSTRING_INDEX来截取分别表示最早时间及最近时间所对应的biz_before, biz_after,这样在Having条件下比较下,便可以一次性的分辨出正向批注的cust_id, in_ucid集合,直接统计对应的正向批注数。

统计正向批注明细数

SELECT SUM(t1.num) as totalCount

FROM (

SELECT cust_id, in_ucid,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_after, '0%') ORDER BY in_postil_id), ',', -1) AS last_biz,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_before, '0%') ORDER BY in_postil_id), ',', 1)  AS first_biz,

SUM(IF(IFNULL(biz_after, '0%') > IFNULL(biz_before, '0%'), 1, 0)) num

FROM tst_in_postil_daily

WHERE add_time>=? AND add_time<?  AND in_ucid = ?

GROUP BY cust_id, in_ucid HAVING IFNULL(last_biz, '0%') > IFNULL(first_biz, '0%')

) t1

备注:

SUM(IF(IFNULL(biz_after, '0%') > IFNULL(biz_before, '0%'), 1, 0)) num

主要用来在分辨出正向批注对应的cust_id, in_ucid后,然后将其跟进明细中,对应商机有提升的记录数统计出来,这样最后统计所有正向批注明细数时,只要对num 求和便可以

展示正向批注明细

SELECT cust_id, in_ucid,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_after, '0%') ORDER BY in_postil_id), ',', -1) AS last_biz,

SUBSTRING_INDEX(GROUP_CONCAT(IFNULL(biz_before, '0%') ORDER BY in_postil_id), ',', 1)  AS first_biz,

SUM(IF(IFNULL(biz_after, '0%') > IFNULL(biz_before, '0%'), 1, 0)) num

FROM tst_in_postil_daily

WHERE add_time>=? AND add_time<?  AND in_ucid = ?

GROUP BY cust_id, in_ucid HAVING IFNULL(last_biz, '0%') > IFNULL(first_biz, '0%')

生成的满足正向批注要求的一个临时表,里面有详细的各个批注明细中商机有提升的明细个数,这样在Java逻辑中,根据查询指定的页面及统计出来的正向批注明细总数,确定该Page的起始行与终止行,然后通过临时表中的num可以确定该Page记录,应该对应哪些cust_id, in_ucid的集合,再去tst_in_postil_daily 表中将该Page的明细取出。

原文地址:https://www.cnblogs.com/shine_cn/p/2225539.html