zoukankan      html  css  js  c++  java
  • SQL优化——SQL语句拆分

    曾经我也感觉我不会写出执行耗时特别长的SQL,直到前几天......

    1、原SQL

    这个SQL实际上的需求就是:根据“条件”去给done_status字段赋值,但是这个条件太复杂了。我们看到,大的方面,就是多个case(order_status取值0-11),但是有的在case的里面进行了嵌套,最深的时候嵌套了5层case。这也是执行特别耗时的原因所在。

    update
    	super4s_order.base_order bo,
    	super4s_order.procurement_order po,
    	super4s_finance.finance_order fo
    set
    	bo.done_status = (
    		case
    			when po.order_status = 0 then 'PROCUREMENT_ORDER_CREATED'
    			when po.order_status = 1 then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    			when po.order_status in (2,3) then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    			 
    			when po.order_status in (11,5,10) then 
    				case 
    					when po.purchase_type = 2 then
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY'
    						end
    					else 
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    						end
    				end
    			when po.order_status in (6,9) then 
    				case 
    					when po.purchase_type = 2 then
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    						end
    					else 
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT'
    						end
    				end
    			when po.order_status = 7 then
    				case 
    					when po.purchase_type = 2 then
    						case
    							when po.apply_pass_time is null 
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_COMPLETE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_COMPLETE'
    						end
    					else 
    						case
    							when po.apply_pass_time is null 
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_COMPLETE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_COMPLETE'
    						end
    				end
    			when po.order_status = 8 then 
    				case
    					when po.purchase_type =2 then
    						case
    							when po.apply_pass_time is null then
    								case
    									when po.in_stock_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_TRANSACTION_CLOSE'
    									else
    										case
    											when bo.finance_code is not null &&  (select count(*) from super4s_finance.finance_order where status in (12,22) and finance_code = bo.finance_code) =1  
    												then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    											else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    										end
    								end
    							else
    								case
    									when po.in_stock_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    									else
    										case
    											when bo.finance_code is not null &&  (select count(*) from super4s_finance.finance_order where status in (12,22) and finance_code = bo.finance_code) =1 
    												then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    											else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    										end
    								end
    						end	
    					else
    						case 
    							when po.apply_pass_time is null then
    								case
    									when bo.finance_code is not null && (select count(*) from super4s_finance.finance_order where status in (12,22) and finance_code = bo.finance_code) =1 
    									then 
    										case 
    											when po.in_stock_time is null 
    												then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    											else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    										end
    									else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_TRANSACTION_CLOSE'
    								end
    							else 
    								case
    									when bo.finance_code is not null && (select count(*) from super4s_finance.finance_order where status in (12,22) and finance_code = bo.finance_code) =1  
    									then 
    										case 
    											when po.in_stock_time is null 
    												then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    											else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    										end
    									else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    								end
    						end
    				end
    		end
    	)
    where
    	bo.order_type = 1
    	and
    	bo.base_order_code = po.base_order_code;
    

    2、优化知道思想

    • 尽量使SQL短而小,更趋于原子化。如果一个sql特别耗时,达到一定时间后,会被系统kill掉;另外,大sql执行时,后面的sql处于阻塞状态,这样会占用很多的系统资源;
    • 减少case嵌套的深度。

    3、优化后的SQL

    因为是根据procurement_order.order_status的不同值(0-11)来给base_order.done_status赋值。所以我们首先是根据order_status对procurement_order的数据量做了统计。对于某一状态,如果数据量相对比较少,我们就不拆分sql,只有对数据量大的sql我们进行拆分。

    -- 1.1.1、base_order采购单状态进度条——非完成、关闭状态
    update
    	super4s_order.base_order bo,
    	super4s_order.procurement_order po
    set
    	bo.done_status = (
    		case
    			when po.order_status = 0 then 'PROCUREMENT_ORDER_CREATED'
    			when po.order_status = 1 then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    			when po.order_status in (2,3) then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    			when po.order_status in (11,5,10) then 
    				case 
    					when po.purchase_type = 2 then
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY'
    						end
    					else 
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    						end
    				end
    			when po.order_status in (6,9) then 
    				case 
    					when po.purchase_type = 2 then
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE'
    						end
    					else 
    						case
    							when po.apply_pass_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT'
    						end
    				end
    		end
    	)
    where
    	bo.order_type = 1
    	and
    	bo.base_order_code = po.base_order_code;
    
    -- 1.1.2、base_order采购单状态进度条——状态
    update
    	super4s_order.base_order bo,
    	super4s_order.procurement_order po
    set
    	bo.done_status = (
    		case 
    			when po.purchase_type = 2 then
    				case
    					when po.apply_pass_time is null 
    						then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_COMPLETE'
    					else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_COMPLETE'
    				end
    		    when po.purchase_type = 5 then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_TRANSACTION_COMPLETE'
    			else 
    				case
    					when po.apply_pass_time is null 
    						then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_COMPLETE'
    					else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_COMPLETE'
    				end
    		end
    	)
    where
    	bo.order_type = 1
    	and
    	po.order_status = 7
    	and
    	bo.base_order_code = po.base_order_code;		
    
    -- 1.1.3、base_order采购单状态进度条——关闭状态&寄售
    update
    	super4s_order.base_order bo,
    	super4s_order.procurement_order po
    set
    	bo.done_status = (
    		case
    			when po.apply_pass_time is null then
    				case
    					when po.in_stock_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_TRANSACTION_CLOSE'
    					else
    						case
    							when bo.finance_code is not null &&  (select count(1) from super4s_finance.finance_order where finance_code = bo.finance_code and status in (12,22)) =1  
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    						end
    				end
    			else
    				case
    					when po.in_stock_time is null then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    					else
    						case
    							when bo.finance_code is not null &&  (select count(1) from super4s_finance.finance_order where finance_code = bo.finance_code and status in (12,22)) =1 
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    						end
    				end
    		end
    	)
    where
    	bo.order_type = 1
    	and
    	po.order_status = 8
    	and
    	po.purchase_type =2
    	and
    	bo.base_order_code = po.base_order_code;
    
    -- 1.1.4、base_order采购单状态进度条——关闭状态&非寄售
    update
    	super4s_order.base_order bo,
    	super4s_order.procurement_order po
    set
    	bo.done_status = (
    		case 
    			when po.apply_pass_time is null then
    				case
    					when bo.finance_code is not null && (select count(1) from super4s_finance.finance_order where finance_code = bo.finance_code and status in (12,22)) =1 
    					then 
    						case 
    							when po.in_stock_time is null 
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    						end
    					else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_TRANSACTION_CLOSE'
    				end
    			else 
    				case
    					when bo.finance_code is not null && (select count(1) from super4s_finance.finance_order where finance_code = bo.finance_code and status in (12,22)) =1  
    					then 
    						case 
    							when po.in_stock_time is null 
    								then 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_TRANSACTION_CLOSE'
    							else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_PENDING_PAYMENT,PROCUREMENT_WAITING_FOR_DELIVERY,PROCUREMENT_TRANSACTION_CLOSE'
    						end
    					else 'PROCUREMENT_ORDER_CREATED,PROCUREMENT_WAIT_APPROVE,PROCUREMENT_TRANSACTION_CLOSE'
    				end
    		end
    	)
    where
    	bo.order_type = 1
    	and
    	po.order_status = 8
    	and
    	po.purchase_type != 2
    	and
    	bo.base_order_code = po.base_order_code;
    

    4、成果

    优化前,35万的数据执行了35分钟;优化后,5秒内执行完毕了!如果各位对这个sql优化还有其他方面的观点,欢迎留言。



    在全栈的道路上,积极向上、成熟稳重、谦虚好学、怀着炽热的心向前方的走得更远。
  • 相关阅读:
    day63_django_html
    day62_django
    day20
    diango_自定义标签问题
    day64_django_orm
    day16_函数嵌套及对象
    day60_django
    pip 安装问题
    day13_文件操作
    文本溢出显示省略号(…) 小坦克
  • 原文地址:https://www.cnblogs.com/DDgougou/p/14097632.html
Copyright © 2011-2022 走看看