溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SQL調(diào)優(yōu)的示例分析

發(fā)布時間:2021-12-29 09:29:38 來源:億速云 閱讀:144 作者:小新 欄目:軟件技術(shù)

這篇文章主要為大家展示了“SQL調(diào)優(yōu)的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“SQL調(diào)優(yōu)的示例分析”這篇文章吧。

環(huán)境:Microsoft SQL Server 2016 (SP2-CU3)企業(yè)版

問題SQL:

select 
	RowNumber = ROW_NUMBER() OVER 
	( 
		-- This ordering is from the various Fulfillment Map sort orders to match the fulfillment app's row order.
		ORDER BY 
			htly.LicenseYear, 
			mht.Name, 
			h.HuntFirstOpenDate, 
			h.DisplayOrder,
			h.HuntCode,
			ci_orderby.LastName,
			ci_orderby.FirstName,
			fmu.FulfillmentMailingUnitID
	),
	ShippingName = ISNULL(fism_aot.ShippingName,  dbo.udf_GetCustomerName(c.CustomerID)),
	FulfillmentMailingUnitID = fmu.FulfillmentMailingUnitID,
	GoID = goid.IdentityValue,
	MailingZip = ISNULL(fism_zc.ZipCode, zc.ZipCode),
	TransactionID = fism_th.TransactionID,
	TransactionHeaderID = fism_th.TransactionHeaderID,
	HuntDate = h.HuntFirstOpenDate,
	HuntCode = h.HuntCode,
	-- Header info
	BatchNumber = fmulg.FulfillmentMailingUnitLockGroupID,
	PrintedByUserName = au.UserName,
	LockedDate = fmulg.LockedDate
from
	dbo.FulfillmentMailingUnitLockGroup fmulg
	cross join dbo.Enum_IdentityType eit
	cross join dbo.Enum_LicenseActionType elat
	inner join dbo.FulfillmentMailingUnitLock fmul
		on fmulg.FulfillmentMailingUnitLockGroupID = fmul.FulfillmentMailingUnitLockGroupID
	inner join dbo.FulfillmentMailingUnit fmu
		on fmul.LockedFulfillmentMailingUnitID = fmu.FulfillmentMailingUnitID
	inner join dbo.ApplicationUser au
		on fmulg.LockedByApplicationUserID = au.ApplicationUserID
	-- Getting to the Transaction Header by FulfillmentInternetSalesMap OR FulfillmentDrawIssuanceMap
	left join dbo.FulfillmentInternetSalesMap fism
		on fmu.FulfillmentMailingUnitID = fism.FulfillmentMailingUnitID
	left join dbo.FulfillmentDrawIssuanceMap fdim
		on fmu.FulfillmentMailingUnitID = fdim.FulfillmentMailingUnitID
		left join dbo.TransactionHeader th	
			on fism.TransactionHeaderID = th.TransactionHeaderID
				or fdim.TransactionHeaderID = th.TransactionHeaderID
	left join dbo.TransactionHeader fdim_th
		on fdim.TransactionHeaderID = fdim_th.TransactionHeaderID
	-- Getting to License from FulfillmentDrawNotificationMap
	left join dbo.FulfillmentDrawNotificationMap fdnm
		on fmu.FulfillmentMailingUnitID = fdnm.FulfillmentMailingUnitID
		left join dbo.DrawTicketLicense fdnm_dtl
			on fdnm.DrawTicketLicenseID = fdnm_dtl.DrawTicketLicenseID 
		left join dbo.License fdnm_l
			on fdnm_dtl.LicenseID = fdnm_l.LicenseID
		left join dbo.DrawTicket fdnm_dt
			on fdnm_dtl.DrawTicketID = fdnm_dt.DrawTicketID
		left join dbo.DrawTicketHuntChoice fdnm_dthc
			on 
				fdnm_dt.DrawTicketID = fdnm_dthc.DrawTicketID
				and
				(
					-- If the draw ticket is a winner, link to the hunt choice that won.
					(fdnm_dt.WasDrawn = 1 and fdnm_dthc.WasDrawn = 1)
					-- Else if the draw ticket was not a winner, link to the first hunt choice since
					-- Losing and Alternate notifications are not valid for multi-choice hunts
					or (fdnm_dt.WasDrawn = 0 and fdnm_dthc.OrderIndex = 1)
				)
		left join dbo.TransactionDetail fdim_td
			on fdim.TransactionHeaderID = fdim_td.TransactionHeaderID
		left join dbo.LicenseAction fdim_la
			on fdim_td.TransactionDetailID = fdim_la.TransactionDetailID
				-- This might be silly since it should only be Issued for issuance... (currently it's sold in the stored proc that issues tags)
				and (fdim_la.LicenseActionTypeID = elat.Sold or fdim_la.LicenseActionTypeID = elat.Issued or fdim_la.LicenseActionTypeID = elat.Duplicated)
		left join dbo.License fdim_l
			on fdim_la.LicenseID = fdim_l.LicenseID
		
		left join dbo.Hunt h
			on fdnm_dthc.HuntID = h.HuntID
				or fdim_l.HuntID = h.HuntID
		left join dbo.HuntTypeLicenseYear htly
			on h.HuntTypeLicenseYearID = htly.HuntTypeLicenseYearID
		left join dbo.MasterHuntType mht
			on htly.MasterHuntTypeID = mht.MasterHuntTypeID
	left join dbo.Customer c
		on fdnm_l.CustomerID = c.CustomerID
			or th.CustomerID = c.CustomerID
	left join dbo.CustomerIndividual ci
		on c.CustomerID = ci.CustomerID
	left join dbo.CustomerIdentity goid
		on c.CustomerID = goid.CustomerID
			and goid.IdentityTypeID = eit.GOID
			and goid.[Status] = 1
	left join dbo.AddressDetail ad
		on c.MailingAddressID = ad.AddressID
			and ad.IsActive = 1
	left join dbo.ZipCode zc
		on ad.ZipCodeID = zc.ZipCodeID
	left join dbo.CustomerIndividual ci_orderby
		on fdnm_l.CustomerID = ci_orderby.CustomerID
			or fdim_th.CustomerID = ci_orderby.CustomerID
	
	left join dbo.TransactionHeader fism_th	
		on fism.TransactionHeaderID = fism_th.TransactionHeaderID
	left join dbo.ActiveOutdoorsTransaction fism_aot
		on fism_aot.TransactionID = fism_th.TransactionID
	left join dbo.AddressDetail fism_ad 
		on fism_aot.ShippingAddressID = fism_ad.AddressID
			and fism_ad.IsActive = 1
	left join dbo.ZipCode fism_zc
		on fism_ad.ZipCodeID = fism_zc.ZipCodeID
	where
		fmulg.FulfillmentMailingUnitLockGroupID = @FulfillmentMailingUnitLockGroupID

該SQL執(zhí)行192s后出記錄,分析一下sql的執(zhí)行計劃:

分析一:

最終的排序消耗了大量的cost:

SQL調(diào)優(yōu)的示例分析

分析二:

該SQL存在大量多表連接,MSSQL引擎由于統(tǒng)計信息的算法單一,在處理大量級聯(lián)連接時,實際數(shù)據(jù)可能嚴(yán)重偏離統(tǒng)計信息

連接中存在Actual Rows和Estimated Rows嚴(yán)重不一致的情況,隨著連接表數(shù)目增加,該不一致更加嚴(yán)重:

SQL調(diào)優(yōu)的示例分析

經(jīng)過分析,優(yōu)化的目標(biāo)是減少多表連接的統(tǒng)計信息不一致導(dǎo)致的執(zhí)行計劃錯誤并且對最終的排序操作進(jìn)行外推。

優(yōu)化的手法主要是利用臨時表固化統(tǒng)計信息,外推排序:

最終優(yōu)化SQL:

select 
	fmu.FulfillmentMailingUnitID
	,elat.Sold
	,elat.Issued
	,elat.Duplicated
	,fmulg.FulfillmentMailingUnitLockGroupID
	,au.UserName
	,fmulg.LockedDate
	,eit.GOID
	into #temp
	from 
	dbo.FulfillmentMailingUnitLockGroup fmulg
	cross join dbo.Enum_IdentityType eit
	cross join dbo.Enum_LicenseActionType elat
	inner join dbo.FulfillmentMailingUnitLock fmul
		on fmulg.FulfillmentMailingUnitLockGroupID = fmul.FulfillmentMailingUnitLockGroupID
	inner join dbo.FulfillmentMailingUnit fmu
		on fmul.LockedFulfillmentMailingUnitID = fmu.FulfillmentMailingUnitID
	inner join dbo.ApplicationUser au
		on fmulg.LockedByApplicationUserID = au.ApplicationUserID
	where
		fmulg.FulfillmentMailingUnitLockGroupID = @FulfillmentMailingUnitLockGroupID
	select 
		fdnm_l.CustomerID fdnm_l_CustomerID,
		th.CustomerID th_CustomerID,
		fdim_th.CustomerID fdim_th_CustomerID,
		t.FulfillmentMailingUnitID,
		h.HuntFirstOpenDate,
		h.HuntCode,
		t.FulfillmentMailingUnitLockGroupID,
		t.UserName,
		LockedDate,
		t.GOID,
		htly.LicenseYear, 
		mht.Name, 
		h.DisplayOrder,
		--ci_orderby.LastName,
		--ci_orderby.FirstName,
		fism.TransactionHeaderID
		into #temp1
		from #temp t
	
		-- Getting to the Transaction Header by FulfillmentInternetSalesMap OR FulfillmentDrawIssuanceMap
		left join dbo.FulfillmentInternetSalesMap fism
			on t.FulfillmentMailingUnitID = fism.FulfillmentMailingUnitID
		left join dbo.FulfillmentDrawIssuanceMap fdim
			on t.FulfillmentMailingUnitID = fdim.FulfillmentMailingUnitID
		left join dbo.TransactionHeader th	
			on fism.TransactionHeaderID = th.TransactionHeaderID
				or fdim.TransactionHeaderID = th.TransactionHeaderID
		left join dbo.TransactionHeader fdim_th
			on fdim.TransactionHeaderID = fdim_th.TransactionHeaderID
		-- Getting to License from FulfillmentDrawNotificationMap
		left join dbo.FulfillmentDrawNotificationMap fdnm
			on t.FulfillmentMailingUnitID = fdnm.FulfillmentMailingUnitID
		left join dbo.DrawTicketLicense fdnm_dtl
			on fdnm.DrawTicketLicenseID = fdnm_dtl.DrawTicketLicenseID 
		left join dbo.License fdnm_l
			on fdnm_dtl.LicenseID = fdnm_l.LicenseID
		left join dbo.DrawTicket fdnm_dt
			on fdnm_dtl.DrawTicketID = fdnm_dt.DrawTicketID
		left join dbo.DrawTicketHuntChoice fdnm_dthc
			on 
				fdnm_dt.DrawTicketID = fdnm_dthc.DrawTicketID
				and
				(
					-- If the draw ticket is a winner, link to the hunt choice that won.
					(fdnm_dt.WasDrawn = 1 and fdnm_dthc.WasDrawn = 1)
					-- Else if the draw ticket was not a winner, link to the first hunt choice since
					-- Losing and Alternate notifications are not valid for multi-choice hunts
					or (fdnm_dt.WasDrawn = 0 and fdnm_dthc.OrderIndex = 1)
				)
		left join dbo.TransactionDetail fdim_td
			on fdim.TransactionHeaderID = fdim_td.TransactionHeaderID
		left join dbo.LicenseAction fdim_la
			on fdim_td.TransactionDetailID = fdim_la.TransactionDetailID
				-- This might be silly since it should only be Issued for issuance... (currently it's sold in the stored proc that issues tags)
				and (fdim_la.LicenseActionTypeID = t.Sold or fdim_la.LicenseActionTypeID = t.Issued or fdim_la.LicenseActionTypeID = t.Duplicated)
		left join dbo.License fdim_l
			on fdim_la.LicenseID = fdim_l.LicenseID
	
		left join dbo.Hunt h
			on fdnm_dthc.HuntID = h.HuntID
				or fdim_l.HuntID = h.HuntID
		left join dbo.HuntTypeLicenseYear htly
			on h.HuntTypeLicenseYearID = htly.HuntTypeLicenseYearID
		left join dbo.MasterHuntType mht
			on htly.MasterHuntTypeID = mht.MasterHuntTypeID
	--set statistics io on
	--set statistics time on
	select 
		t1.LicenseYear,
		t1.Name, 
		t1.DisplayOrder,
		c.CustomerID,
		t1.FulfillmentMailingUnitID,
		t1.GOID,
		zc.ZipCode,
		t1.HuntFirstOpenDate,
		t1.HuntCode,
		t1.FulfillmentMailingUnitLockGroupID,
		t1.UserName,
		t1.LockedDate,
		t1.fdnm_l_CustomerID,
		t1.fdim_th_CustomerID,
		t1.TransactionHeaderID
	 into #temp2
	 from #temp1 t1
	
		-- Getting to Cusotmer from the joined transaction header or the license from the DrawTicketLicense
		left join dbo.Customer c
			on t1.fdnm_l_CustomerID = c.CustomerID
				or t1.th_CustomerID = c.CustomerID
		left join dbo.CustomerIndividual ci
			on c.CustomerID = ci.CustomerID
		
		left join dbo.AddressDetail ad
			on c.MailingAddressID = ad.AddressID
				and ad.IsActive = 1
		left join dbo.ZipCode zc
			on ad.ZipCodeID = zc.ZipCodeID
		
	select 
		t2.LicenseYear,
		t2.Name, 
		t2.DisplayOrder,
		ci_orderby.LastName,
		ci_orderby.FirstName,
		ShippingName = ISNULL(fism_aot.ShippingName,  dbo.udf_GetCustomerName(t2.CustomerID)),
		FulfillmentMailingUnitID = t2.FulfillmentMailingUnitID,
		GoID = goid.IdentityValue,
		MailingZip = ISNULL(fism_zc.ZipCode, t2.ZipCode),
		TransactionID = fism_th.TransactionID,
		TransactionHeaderID = fism_th.TransactionHeaderID,
		HuntDate = t2.HuntFirstOpenDate,
		HuntCode = t2.HuntCode,
		-- Header info
		BatchNumber = t2.FulfillmentMailingUnitLockGroupID,
		PrintedByUserName = t2.UserName,
		LockedDate = t2.LockedDate 
	into #temp3
	from #temp2 t2
			left join dbo.CustomerIdentity goid
				on t2.CustomerID = goid.CustomerID
				and goid.IdentityTypeID = t2.GOID 
				and goid.[Status] = 1
			left join dbo.CustomerIndividual ci_orderby
				on t2.fdnm_l_CustomerID = ci_orderby.CustomerID
					or t2.fdim_th_CustomerID = ci_orderby.CustomerID
	
			left join dbo.TransactionHeader fism_th	
				on t2.TransactionHeaderID = fism_th.TransactionHeaderID
			left join dbo.ActiveOutdoorsTransaction fism_aot
				on fism_aot.TransactionID = fism_th.TransactionID
			left join dbo.AddressDetail fism_ad 
				on fism_aot.ShippingAddressID = fism_ad.AddressID
					and fism_ad.IsActive = 1
			left join dbo.ZipCode fism_zc
				on fism_ad.ZipCodeID = fism_zc.ZipCodeID
	select	RowNumber = ROW_NUMBER() OVER 
		( 
			-- This ordering is from the various Fulfillment Map sort orders to match the fulfillment app's row order.
			ORDER BY 
				t3.LicenseYear, 
				t3.Name, 
				t3.HuntDate, 
				t3.DisplayOrder,
				t3.HuntCode,
				t3.LastName,
				t3.FirstName,
				t3.FulfillmentMailingUnitID
		),
		ShippingName,
		FulfillmentMailingUnitID,
		GoID,
		MailingZip,
		TransactionID,
		TransactionHeaderID,
		HuntDate,
		HuntCode,
		-- Header info
		BatchNumber,
		PrintedByUserName,
		LockedDate
	from #temp3 t3
	drop table #temp
	drop table #temp1
	drop table #temp2
	drop table #temp3

經(jīng)過測試,執(zhí)行時間由192秒降低到2秒。

以上是“SQL調(diào)優(yōu)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

sql
AI