• 报表项目总结


    这个项目做的很累,主要参与做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的明细取出。

  • 相关阅读:
    C#读取Excel设置(亲测可用)
    vue element-ui的对话框dialog没有height怎么解决?
    sqlserver不同服务器的不同数据库如何复制
    es6-对象与数组的解构赋值
    win10电脑上不了网了
    sqlserver数据库备份之后再还原
    “相对路径”以及“绝对路径”使用之坑
    sqlserver表-添加大量测试数据
    vue文件命名规范
    Git大小写问题
  • 原文地址:https://www.cnblogs.com/shine_cn/p/2225539.html
Copyright © 2020-2023  润新知