请教这段 SQL 如何改写成 SPL 更合理
SELECT
date_format( d.date_id, '%m/%d' ) date_id,
ifnull( d.rc_cb, 0 ) rc_cb,
ifnull( d.zd_cb, 0 ) zd_cb,
ifnull( d.zd_cb_cq, 0 ) zd_cb_cq,
ifnull( d.gg_zyc, 0 ) gg_zyc,
ifnull( d.kx, 0 ) kx,
ifnull( d.yg_gh, 0 ) + ifnull( d.cq_xj, 0 ) + ifnull( d.prj_fjf, 0 ) AS qt,-- 其他
ifnull( d.rc_cb, 0 ) + ifnull( d.zd_cb, 0 ) + ifnull( d.zd_cb_cq, 0 ) + ifnull( d.gg_zyc, 0 ) + ifnull( d.kx, 0 ) + ifnull( d.yg_gh, 0 ) + ifnull( d.cq_xj, 0 ) + ifnull( d.kxt, 0 )+ ifnull( d.prj_fjf, 0 ) AS hj,
ifnull( d.kxt, 0 ) kxt
FROM
(
SELECT
b.DATE_ID,
sum( CASE WHEN b1.prj_type IN ( 'CR' ) AND b1.prj_name LIKE '%储备%' THEN 1 ELSE 0 END ) zd_cb,
sum( CASE WHEN b1.prj_type IN ( 'GP', 'RP' ) AND b1.prj_name LIKE '%被动储备%' THEN 1 ELSE 0 END ) zd_cb_cq,
sum(
CASE
WHEN REPLACE ( b1.JOIN_DATE, '-', '' ) <= b.DATE_ID AND REPLACE ( b1.START_DATE, '-', '' ) > b.DATE_ID THEN
1 ELSE 0
END
) rc_cb,
sum( CASE WHEN b1.prj_type IN ( 'GP', 'RP' ) AND b1.prj_name LIKE '%公共资源池%' THEN 1 ELSE 0 END ) gg_zyc,
sum( CASE WHEN b1.prj_type = 'I' THEN 1 ELSE 0 END ) kx,
sum( CASE WHEN b1.prj_type IN ( 'SR', 'LR' ) AND b1.prj_name LIKE '%员工关怀%' THEN 1 ELSE 0 END ) yg_gh,
sum( CASE WHEN b1.prj_type IN ( 'SR', 'LR' ) AND b1.prj_name LIKE '%长期休假%' THEN 1 ELSE 0 END ) cq_xj,
sum( CASE WHEN b1.prj_type IN ( 'GP', 'RP' ) AND b1.prj_name LIKE '%可协调资源池%' THEN 1 ELSE 0 END ) kxt,
sum(
CASE
WHEN b1.prj_type IN ( 'C', 'C1' )
AND ((
ifnull( b1.START_DATE, '' ) = ''
AND ifnull( b1.END_DATE, '' ) = ''
)
OR ( b1.END_DATE < b1.leave_date AND b1.END_DATE = b.DATE_ID )) THEN
1 ELSE 0
END
) prj_fjf
FROM
calendar_d b,
(
SELECT
a.emp_no,
a.join_date,
a.leave_date,
a.start_date,
a.end_date,
a1.prj_name,
a1.prj_type,
a2.parentNo bu
FROM
emp_prj a
LEFT JOIN prj_info a1 ON a.prj_no = a1.prj_no
LEFT JOIN dept a2 ON a1.ss_dept_id = a2.deptno
WHERE
((
'${sdate}' <= REPLACE ( a.join_date, '-', '' ) AND '${edate}' >= REPLACE ( a.join_date, '-', '' )
AND '${edate}' <= REPLACE ( a.leave_date, '-', '' )) OR ( '${sdate}' >= REPLACE ( a.join_date, '-', '' )
AND '${edate}' <= REPLACE ( a.leave_date, '-', '' )) OR ( '${sdate}' >= REPLACE ( a.join_date, '-', '' )
AND '${sdate}' <= REPLACE ( a.leave_date, '-', '' ) AND '${edate}' >= REPLACE ( a.leave_date, '-', '' ))
OR (
'${sdate}' <= REPLACE ( a.join_date, '-', '' ) AND '${edate}' >= REPLACE ( a.leave_date, '-', '' ))
)
AND
IF
( '${buno}' = 'BG000', a2.parentNo LIKE 'BU%', a2.parentNo = '${buno}' )
) b1
WHERE
REPLACE ( b1.JOIN_DATE, '-', '' ) <= b.DATE_ID AND REPLACE ( b1.LEAVE_DATE, '-', '' ) >= b.DATE_ID
AND b.DATE_ID >= '${sdate}'
AND b.DATE_ID <= '${edate}'
AND
IF
( '${buno}' = 'BG000', b1.bu LIKE 'BU%', b1.bu = '${buno}' )
GROUP BY
b.DATE_ID
) d
涉及的 4 个表都不大,数据量如下:
select count(*) from calendar_d 3675
select count(*) from emp_prj 98159
select count(*) from prj_info 11471
select count(*) from dept 2051
其中 calendar_d 的主键是 DATE_ID。
但后面关联以后的结果集会比较大,现在查询的时间在 150 秒以上。请问如何使用集算器改写更合理?预期查询时间在 1 秒以内。
使用 SPL 改写的建议如下:
1. 日期如果是字串,应该修改参数去匹配字段的格式,而不是用 replace 去改字段,否则造成的计算量太多。这一条在 SQL 里也可以实现
2. prj_info 相关的那些 case 条件可以先算好,做成 boolean 型计算列,LIKE 和 IN 计算都很慢。
3. dept 先按条件过滤
4. calendar_d 按 date_id 排序
5. 用时间条件和 switch@i(dept) 过滤 emp_prj 再 switch 关联 prj_info
6. 针对第 5 步的结果用循环函数寻找在第 4 步结果的匹配记录,第 4 步已排序,可以用二分法寻找。再用 groups 计算分组汇总
7. 最后再 new 一下结果集
第 2/4 步可以用 @m 并行,第 5/6 步可以用内存多路游标并行。
如果数据可以先内存化,还可以将 emp_prj 和 dept/prj_inf 做好预关联。