您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“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存在大量多表連接,MSSQL引擎由于統(tǒng)計信息的算法單一,在處理大量級聯(lián)連接時,實際數(shù)據(jù)可能嚴(yán)重偏離統(tǒng)計信息
連接中存在Actual Rows和Estimated Rows嚴(yán)重不一致的情況,隨著連接表數(shù)目增加,該不一致更加嚴(yán)重:
經(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è)資訊頻道!
免責(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)容。