1. 程式人生 > >一次成功的sql優化,2個表joinI/O 極大,大約9million

一次成功的sql優化,2個表joinI/O 極大,大約9million

原始sql:

更新#result表,更新warr_bal.I/O大的原因是CIS..trans_acd_bal資料量太大,

並且#result表的資料量並不大,且如果有重複的資料,sum出來的結果呈倍數增長。

	CREATE TABLE #scm(
		scm_no int NULL
		,amt money NULL
		)

	INSERT INTO #scm
	SELECT scm_no
		,sum(isnull(gl_amt, 0))
	FROM #result t
	INNER JOIN CIS..trans_acd_bal ta
		ON ta.gl_project = t.scm_no
WHERE ta.gl_year = @pre_year AND ta.gl_month = @pre_month GROUP BY scm_no UPDATE #result SET warr_bal = scm.amt FROM #result t INNER JOIN #scm scm ON t.scm_no = scm.scm_no
修改後的sql如下:I/O小了,並且時間也減少。

迴圈的時候最重要的是紅色的sql語句

	-----------update trans_bal from CIS..trans_acd_bal begin
	DECLARE @max_idn int
		,@min_idn int
		,@bal_amt money
		,@scm_no int

	SELECT @min_idn = isnull(min(idn), 0)
	FROM #result

	SELECT @max_idn = isnull(max(idn), 0) + 1
	FROM #result

	WHILE (@min_idn < @max_idn)
	BEGIN
		SELECT @scm_no = isnull(scm_no, 0)
			,@bal_amt = warr_bal
		FROM #result t
		WHERE t.idn = @min_idn

		IF (@bal_amt IS NULL)
BEGIN SELECT @bal_amt = sum(gl_amt) FROM CIS..trans_acd_bal ta WHERE ta.gl_year = @pre_year AND ta.gl_month = @pre_month AND ta.gl_project = @scm_no UPDATE #result SET warr_bal = @bal_amt FROM #result t WHERE t.idn = @min_idn OR t.scm_no = @scm_no END SELECT @min_idn = min(idn) FROM #result WHERE idn > @min_idn END -----------update trans_bal from CIS..trans_acd_bal end


第二個例子:

優化前sql,2個表直接inner join I/O 異常大。

journal_entry是個大表,且有索引。

 SELECT b.dept_no
            ,max(b.dept_name) AS dept_name
    FROM journal_entry a
    INNER JOIN department_info b
            ON a.gl_department = b.dept_no
    WHERE a.gl_acct_no > 700000
    GROUP BY b.dept_no

優化後i/O降低了大概只有原來1/10的I/O,
 SELECT a.gl_department as dept_no
            ,(select max(b.dept_name) from department_info b where a.gl_department = b.dept_no)  AS dept_name
    FROM journal_entry a
    WHERE a.gl_acct_no > 700000
    GROUP BY a.gl_department


第三個例子,普通取模迴圈

declare @iloop int,@ibatch int
SET @iloop = 0

	SELECT @ibatch = (count(*) / 200000) + 1
	FROM #pay_tmp

	WHILE @iloop < @ibatch
	BEGIN
		EXEC (
				"
		UPDATE #pay_tmp
		SET payment = payment + pay_amt
		FROM #pay_tmp a1701250030(index id_1)
		INNER JOIN #temp_pay b(index id_1)
			ON a1701250030.order_no = b.order_no
				AND a1701250030.order_type = b.order_type
		WHERE abs(isnull(a1701250030.order_no, 0)) % @ibatch = @iloop
		"
				)

		EXEC (
				"
		DELETE #temp_pay
		FROM #pay_tmp a1701250031(index id_1)
		INNER JOIN #temp_pay b(index id_1)
			ON a1701250031.order_no = b.order_no
				AND a1701250031.order_type = b.order_type
		WHERE abs(isnull(a1701250031.order_no, 0)) % @ibatch = @iloop
		"
				)

		INSERT #pay_tmp(
			order_type
			,order_no
			,payment
			)
		SELECT order_type
			,order_no
			,pay_amt
		FROM #temp_pay a
		WHERE abs(isnull(a.order_no, 0)) % @ibatch = @iloop

		SET @iloop = @iloop + 1
	END

第四個例子:old sql update 太大,為降低I/O,增加臨時表。

old sql 每個都join 去sum,所以I/O 太大

UPDATE #result
	SET w0 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 0
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w1 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 1
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w2 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 2
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w3 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 3
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w4 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 4
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w5 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 5
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w6 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 6
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w7 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 7
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w8 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 8
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w9 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 9
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w10 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 10
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w11 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 11
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w12 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 12
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w13 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 13
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w14 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 14
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w15 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 15
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w16 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 16
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w17 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 17
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w18 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 18
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w19 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 19
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w20 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 20
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w21 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 21
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w22 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 22
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w23 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 23
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w24 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 24
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w25 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 25
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
		,w26 = (
			SELECT s.reqQty
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND s.idx = 26
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			)
	FROM #result r

	UPDATE #result
	SET forecast_total = (
			SELECT sum(isnull(s.reqQty, 0))
			FROM #res s
			WHERE r.cust_no = s.custNo
				AND r.group_id = s.group_id
				AND r.loc_no = s.loc_no
				AND r.sku_no = s.skuNo
				AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')
			GROUP BY s.custNo
				,s.group_id
				,s.loc_no
				,s.skuNo
				,isnull(ltrim(rtrim(s.refNo)), '')
			)
	FROM #result r

新的sql,放入臨時表,把結果計算出來後,再去update
insert into  #temptable
SELECT s.custNo
	,s.group_id
	,s.loc_no
	,s.skuNo
	,isnull(ltrim(rtrim(s.refNo)), '') AS refNo
	,sum(CASE 
			WHEN s.idx = 0
				THEN s.reqQty
			END) AS w0
	,sum(CASE 
			WHEN s.idx = 1
				THEN s.reqQty
			END) AS w1
	,sum(CASE 
			WHEN s.idx = 2
				THEN s.reqQty
			END) AS w2
	,sum(CASE 
			WHEN s.idx = 3
				THEN s.reqQty
			END) AS w3
	,sum(CASE 
			WHEN s.idx = 4
				THEN s.reqQty
			END) AS w4
	,sum(CASE 
			WHEN s.idx = 5
				THEN s.reqQty
			END) AS w5
	,sum(CASE 
			WHEN s.idx = 6
				THEN s.reqQty
			END) AS w6
	,sum(CASE 
			WHEN s.idx = 7
				THEN s.reqQty
			END) AS w7
	,sum(CASE 
			WHEN s.idx = 8
				THEN s.reqQty
			END) AS w8
	,sum(CASE 
			WHEN s.idx = 9
				THEN s.reqQty
			END) AS w9
	,sum(CASE 
			WHEN s.idx = 10
				THEN s.reqQty
			END) AS w10
	,sum(CASE 
			WHEN s.idx = 11
				THEN s.reqQty
			END) AS w11
	,sum(CASE 
			WHEN s.idx = 12
				THEN s.reqQty
			END) AS w12
	,sum(CASE 
			WHEN s.idx = 13
				THEN s.reqQty
			END) AS w13
	,sum(CASE 
			WHEN s.idx = 14
				THEN s.reqQty
			END) AS w14
	,sum(CASE 
			WHEN s.idx = 15
				THEN s.reqQty
			END) AS w15
	,sum(CASE 
			WHEN s.idx = 16
				THEN s.reqQty
			END) AS w16
	,sum(CASE 
			WHEN s.idx = 17
				THEN s.reqQty
			END) AS w17
	,sum(CASE 
			WHEN s.idx = 18
				THEN s.reqQty
			END) AS w18
	,sum(CASE 
			WHEN s.idx = 19
				THEN s.reqQty
			END) AS w19
	,sum(CASE 
			WHEN s.idx = 20
				THEN s.reqQty
			END) AS w20
	,sum(CASE 
			WHEN s.idx = 21
				THEN s.reqQty
			END) AS w21
	,sum(CASE 
			WHEN s.idx = 22
				THEN s.reqQty
			END) AS w22
	,sum(CASE 
			WHEN s.idx = 23
				THEN s.reqQty
			END) AS w23
	,sum(CASE 
			WHEN s.idx = 24
				THEN s.reqQty
			END) AS w24
	,sum(CASE 
			WHEN s.idx = 25
				THEN s.reqQty
			END) AS w25
	,sum(CASE 
			WHEN s.idx = 26
				THEN s.reqQty
			END) AS w26
	,sum(s.reqQty) as wall
FROM #res s
GROUP BY s.custNo
	,s.group_id
	,s.loc_no
	,s.skuNo
	,isnull(ltrim(rtrim(s.refNo)), '')

UPDATE #result
SET w0 = s.w0
	,w1 = s.w1
	,w2 = s.w2
	,w3 = s.w3
	,w4 = s.w4
	,w5 = s.w5
	,w6 = s.w6
	,w7 = s.w7
	,w8 = s.w8
	,w9 = s.w9
	,w10 = s.w10
	,w11 = s.w11
	,w12 = s.w12
	,w13 = s.w13
	,w14 = s.w14
	,w15 = s.w15
	,w16 = s.w16
	,w17 = s.w17
	,w18 = s.w18
	,w19 = s.w19
	,w20 = s.w20
	,w21 = s.w21
	,w22 = s.w22
	,w23 = s.w23
	,w24 = s.w24
	,w25 = s.w25
	,w26 = s.w26
	,forecast_total = s.wall
FROM #result r
INNER JOIN #temptable s
	ON r.cust_no = s.custNo
		AND r.group_id = s.group_id
		AND r.loc_no = s.loc_no
		AND r.sku_no = s.skuNo
		AND isnull(ltrim(rtrim(r.ref_no)), '') = isnull(ltrim(rtrim(s.refNo)), '')