需要做一个报表,多表联合查询,并且数据量都在几十万到百万以上。
二、问题描述 2.1
例如,做一个报表,游戏报表,假如一个游戏有关卡表gate,关卡内含有任务表task,这时候需要按天统计,一个人在哪一天通关了什么关卡,各个关卡任务的完成情况。
这时候,还会有要统计人的通关情况还需要,gate_user 表,task_user表
这时候如果不考虑按天切片,我们可以得出这样的sql
select *from gate_user user left join gate gate on user.gateId=gate.id
where gate.status ='已完成'.
如果要按天完成,这时候有两种方案,
2.2.1 关卡或者人变动的时候插入历史表,也就是有 gate_user_his 和 gate_his,然后关卡变动就往这两个表插数据,
然后查询的时候取最新的记录。
SELECT
*
FROM
(
SELECT
user.*
FROM
gate_user_his user
INNER JOIN (SELECT max(insertTime)) inserttime,
user1.id,user1.userid
FROM
gate_user_his user1
GROUP BY
user1.id,user1.userid) user1 ON user1.id = user1.id
AND user.inserttime = user1 .inserttime and user.userid=user1.userid
) user
LEFT JOIN (
SELECT
gate.*
FROM
gate_his gate
INNER JOIN (
SELECT
max(inserttime) inserttime,
gate.id
FROM
gate_his gaet1
GROUP BY
gate.id
) gate on gate .id= gate1.id and gate.inserttime= gate1.inserttime
) gate gate ON USER.gateId = gate.id
WHERE
gate. STATUS = '已完成'.
2.2.2 按天切片统计
该种方案,每天凌晨把上一天的数据丢一份到历史表里面,
select *from gate_user_his user left join gate_his gate on user.gateId=gate.id
where gate.status =‘已完成’.
and inserttime=‘统计日期’
1.我当时考虑到按天每天塞一份数据,会有很多冗余的数据,而且(关卡X任务X人数)user_task表数据会非常多,采用了第一种方案,
2.然后数据量一上来,就查不动了,不管加索引还是怎么优化都不行,而此时代码已经写了很多,很难再改了。
3.而且变动的时候插入,和业务代码高度耦合,很容易出问题,这也是一大缺点。
4.sql 复杂难以维护。
解决方案:
1.最后,应该改为第二种方案,无论是走索引,还是sql复杂度,还是代码耦合性都远胜于第一种。
2.当然第二种就是会有非常多的冗余数据,当时就是产品也没有说限制查询的天数,担心表很容易就爆满,没有采用,其实这时候我们作为技术人员应该提出要限制查询的天数,而不是采用我之前用的方案,导致后患无穷。
3.写出来给大家一个参考避免走我的坑。
4.还有就是像这种报表的统计,尽量不要有逻辑删除的字段,如果有逻辑删除还要加上一个deleted=0,一般来说删除的数据都是少于不删除的,这时候索引就无效了,也会导致报表很慢,delete的数据尽量移除出统计表,用另外的表去存,而不是用统计的报表存。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)