一次性能优化(主要是sql查询优化,把or 改成 union all)

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逻辑这块,还有待优化的空间,不知道大家有什么意见吗,个人目前没有思路:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值