1、原代码如下:
(1)、业务controller层,调用了3次service方法访问数据: ordersService.getBussOrders ( ...)
(2)、而ordersService中的,service层调用了访问数据库方法,在ordersDao.listBussPOrders()方法里面,最后执行的是mybatis查询
(3)mybatis中的*mapper.xml文件:
原有的业务含义应该是,分别在以下3个参数有值的时候departId、sponsorId、jointlyId,访问了3次数据库查询,然后把结果集拼接起来到一个集合中。
(4)、执行的完整sql如下:
SELECT
*
FROM
(
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.sponsor_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( H1.cust_name ), ',', GROUP_CONCAT( H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( H1.cust_name ), GROUP_CONCAT( H2.com_fullname ) )
END 'hgMan',
GROUP_CONCAT( L.delivery_place ) AS deliverPlace,
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN lease_info AS L ON A.buss_no = L.buss_no
AND L.lease_type = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
GROUP BY
A.buss_no
ORDER BY
B.create_time DESC
) AS SUB
GROUP BY
SUB.buss_no
ORDER BY
SUB.create_time DESC
(在最坏情况下,当departId、sponsorId、jointlyId都没有值,sql未拼接字段的时候),单条sql执行时间2.5秒左右:
如果说在步骤1、(1)代码中,查询3次,那么光是3行代码执行查询3次sql的时间,就7.5秒了,再加上其它业务处理,前后端交互响应时间,网络延时,前端页面加载数据,就会变得很慢了。
(5)、如下是我在生产环境中,翻页查询,调用该接口,总响应时间,几次消耗总时间都在10秒以上:
2、优化:
(1)、先优化代码,只和数据库查询交互一次:
(2)、优化sql,只查询一次以后,需要sql把3种情况的并集,都返回,于是首先想到了or用法:
先把子查询中的order by 去掉,因为最外层有order by 排序了,没有必要两次排序:
改mybatis,把之前的and改成or:
sql代码改成or以后如下:
SELECT
SUB.*,
GROUP_CONCAT( LS.delivery_place ) AS deliverPlaces
FROM
(
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND (A.sponsor_id = 'x' OR A.jointly_id = 'xx' OR A.depart_id = 'xxx' )
GROUP BY
A.buss_no
) AS SUB
INNER JOIN lease_info LS ON SUB.buss_no = LS.buss_no
AND LS.lease_type = '1'
GROUP BY
SUB.buss_no
ORDER BY
SUB.create_time DESC
limit 1,10
测试执行时间,在1.5秒左右
(3)如果不用or,还有一种方案,就是换成union all,测试一下执行时间,
sql代码如下:
SELECT
SUB.*,
GROUP_CONCAT( LS.delivery_place ) AS deliverPlaces
FROM
(
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.sponsor_id = 'x'
GROUP BY
A.buss_no
UNION ALL
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.jointly_id = 'xx'
GROUP BY
A.buss_no
UNION ALL
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.depart_id = 'xxx'
GROUP BY
A.buss_no
) AS SUB
INNER JOIN lease_info LS ON SUB.buss_no = LS.buss_no
AND LS.lease_type = '1'
GROUP BY
SUB.buss_no
ORDER BY
SUB.create_time DESC
limit 1,10
多次测试执行时间, 都在0.9秒左右:
(4)、因为sql最后使用了limit分页,再给单个UNION ALL 子句再加上 limit 条数限制,单个子集合查出来的结果就少了
(虽然这样sql更快,但是最后会影响分页显示结果,看业务情况使用):
SELECT
SUB.*,
GROUP_CONCAT( LS.delivery_place ) AS deliverPlaces
FROM
(
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.sponsor_id = 'x'
GROUP BY
A.buss_no limit 1,10
UNION ALL
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.jointly_id = 'xx'
GROUP BY
A.buss_no limit 1,10
UNION ALL
SELECT
B.id,
A.buss_no,
A.task_type,
A.task_status,
A.start_date,
B.create_time,
A.depart_id,
A.sponsor_id,
A.jointly_id,
A.sponsor_name,
A.jointly_name,
A.raise_funds,
A.lease_amount,
B.owner_id,
B.owner_name,
B.cust_name,
C.start_date c_start_date,
CASE
WHEN (
GROUP_CONCAT( DISTINCT H1.cust_name ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H1.cust_name ) ) ) > 0
AND GROUP_CONCAT( DISTINCT H2.com_fullname ) IS NOT NULL
AND LENGTH( trim( GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ) > 0
) THEN
CONCAT( GROUP_CONCAT( DISTINCT H1.cust_name ), ',', GROUP_CONCAT( DISTINCT H2.com_fullname ) ) ELSE ifnull( GROUP_CONCAT( DISTINCT H1.cust_name ), GROUP_CONCAT( DISTINCT H2.com_fullname ) )
END 'hgMan',
DATE_FORMAT( W.create_time, '%Y-%m-%d %H:%i:%s' ) AS auditTime
FROM
orders A
INNER JOIN wf_task B ON A.buss_no = B.buss_no
LEFT JOIN contract_clause AS C ON A.buss_no = C.buss_no
LEFT JOIN cust_nature AS H1 ON A.buss_no = H1.buss_no
AND H1.buss_type = 'HG'
AND H1.STATUS = '1'
LEFT JOIN cust_legal AS H2 ON A.buss_no = H2.buss_no
AND H2.buss_type = 'HG'
AND H2.STATUS = '1'
LEFT JOIN wf_task AS W ON A.buss_no = W.buss_no
AND W.task_type = '30'
AND W.is_current = "Y"
WHERE
B.is_current = "Y"
AND A.STATUS = "1"
AND A.task_type = B.task_type
AND A.task_status = B.STATUS
AND A.depart_id = 'xxx'
GROUP BY
A.buss_no
limit 1,10
) AS SUB
INNER JOIN lease_info LS ON SUB.buss_no = LS.buss_no
AND LS.lease_type = '1'
GROUP BY
SUB.buss_no
ORDER BY
SUB.create_time DESC
limit 1,10
执行测试时间如下,多次测试都在 0.4~0.7秒之间:
(5)上了一下测试环境,页面翻页效果还是比较理想的,响应都在几毫秒之内(跟生产环境数据量不一样,但是肯定会比之前应该要快不少):
这次简单优化,就完成了;可以达到预期查询的性能效果,等待上线验证效果;
to do:
但是个人感觉sql的 case when逻辑这块,还有待优化的空间,不知道大家有什么意见吗,个人目前没有思路: