无需使用or运算符即可提高性能的另一种方式

时间:2019-01-29 15:21:35

标签: sql-server performance tsql performance-testing sql-tuning

此存储过程是我正在处理的报告的一部分。因此,准确地说,它运行非常慢,运行非常慢,需要48分钟。通过在下面看到的联接中删除or运算符,我可以在6秒钟内运行它。现在,它不返回重复项,而是返回两个表中的数据,这为我的结果集中添加了更多行。问题是  两个联接,分别是FinancialTransactions ft,FinancialTransactions ftRec

我尝试使用CTE。我将联接拆分并合并所有它们。我无法向查询添加索引或创建任何视图。我还加入了另一个表以及另一个视图,该视图返回了更多需要的行。

                                   Before Fix



  SELECT DISTINCT 
             1 as SourceId,
             l.LotID as 'LotId',
             r.Id as 'RecoveryId',
             acc.AccountName as 'Account',
             r.BillingCode as BillingCode,
             r.ProjectCode as ProjectCode,
             a.AssetID as 'SSE Number',
             ' ' as 'ParentSSENumber',
             COALESCE(ft.InvoiceNumber,ftrec.InvoiceNumber) as InvoiceNumber, 
             COALESCE(ft.InvoicedOn,ftrec.InvoicedOn) as InvoiceDate, 
             a.Class AS Category,
             a.Manufacturer,
             a.Product AS Model, 
             a.ProductNumber AS ModelNum,
             a.SerialNumber AS SerialNum, 
             a.CustomerAssetNumber AS CustAssetTag, 
             a.Weight, 
             @WeightMeasure AS WeightMeasurement,
            CASE a.ClassID --a.LockedStatus 
                WHEN 919
                    THEN CASE hdd.Disposition 
                         WHEN 'Inventory' 
                         THEN
                             CASE  
                             WHEN -ft.Rate > 0 
                                THEN 'Resale'
                                ELSE 'Active' END 
                          ELSE hdd.Disposition END
                ELSE 
                    CASE --ISNULL(A.LockedStatus, - 1) 
                        WHEN A.LockedStatus = -1  THEN 'InProduction' 
                        WHEN A.LockedStatus = 1 THEN 'Active' 
                        WHEN A.LockedStatus = 2 THEN 'On Hold' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 7 THEN 'Redeployment' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 12 THEN 'Donation' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 11 THEN 'Legal Hold Release' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType NOT IN (7,11,12) THEN 'Sold' 
                        WHEN A.LockedStatus = 4 THEN 'Upgrade' 
                        WHEN A.LockedStatus = 5 THEN 'Recycled' 
                        WHEN A.LockedStatus = 6 THEN 'Sold Off-site' 
                        ELSE '' 
                    END
                 END
                AS Disposition,
            CASE WHEN a.LockedStatus = 5
                 THEN ftrec.CreatedOn
                 ELSE iph_gen.shipDate END AS DispositionDate,               
            '' AS Comments, --REPLACE(r.AdditionalNotes , CHAR(10), '') as Comments,
            isnull(GTu.Name, 'N/A') AS FinalGrade,
              ' ', ' ',
              ISNULL(CASE ftRec.RateTypeID WHEN 1 THEN a.Weight ELSE 1 END * ftRec.Rate,0)  AS RecyclingFees,
            --  ISNULL(ft.RemarketingPercentage,0),
              isnull(ft.Rate,0) AS RemarketingCredit,
              --isnull(gt.Name, 'N/A') AS RegisteredGrade,
              --' ', 
             0.00 as LeaseReturnFee,
             CASE WHEN iph_gen.PurchaseType = 7 THEN ISNULL(ipds_gen.Price,0)
                 ELSE 0.00
                 END AS RedploymentFee,
             CASE WHEN ccsg.GroupName LIKE '%Donation%' THEN
                 CASE WHEN iph_gen.PurchaseType = 12 THEN ISNULL(ipds_gen.Price,0)
                 ELSE 0.00
                 END ELSE 0.00
                 END AS DonationFee

        FROM vAssetSimpleView a 
        INNER JOIN itTransactionProcess AS tp ON tp.TransactionID = a.OrigTransactionID 
        INNER JOIN itLots AS l ON l.LotID = tp.LotNumber 
        LEFT JOIN [10.10.1.188,13151].Adviser.dbo.Recovery r on l.LotID = r.MRMLotId
        --LEFT JOIN [54.84.218.110,13151].Adviser.dbo.Account acc on r.AccountId = acc.Id
        LEFT OUTER JOIN AccountLocationOrderNo AS alon ON alon.LotID = l.LotID 
        LEFT JOIN AccountLocation AS al ON al.LocationID = l.LocationID 
        LEFT JOIN Account acc ON al.accountId = acc.AccountID
        LEFT JOIN itDocks AS d ON d.DockID = l.DockScheduledOn 
        LEFT OUTER JOIN Contact AS c ON al.Contact_Onsite = c.ContactID 
        LEFT OUTER JOIN itGradeTypes AS g ON g.RecID = a.Grade
        --JOINS FOR ORDERS
        LEFT JOIN itPurchaseDetails ipd_gen on ipd_gen.assetid = a.assetid
        LEFT JOIN itPurchaseDetailService ipds_gen on ipd_gen.RecID = ipds_gen.PurchaseDetailRecId
        LEFT JOIN ContractCustomServiceGroups ccsg on ccsg.recid = ipds_gen.ServiceGroupId
                        --AND ipds_donation.ServiceGroupId IN (SELECT  RecID FROM [ContractCustomServiceGroups]  WHERE GroupName Like '%Donation%')
        LEFT JOIN itPurchaseHeader iph_gen on ipd_gen.PurchaseHeaderRecID = iph_gen.RecID
                        --AND iph_donation.PurchaseType = 12
        --END JOINS FOR ORDERS
        LEFT OUTER JOIN dbo.Reporting_Inventory_Harddrives hdd ON hdd.AssetID = a.AssetID
        --LEFT OUTER JOIN vAssetServicesByType vast ON a.AssetID = vast.AssetRecId
        --OUTER APPLY
        --(
        --  SELECT ph.RecID AS OrderID, v.VendorName, ph.OrderDate,ph.shipdate, cup.FirstName + ' ' + cup.LastName AS SalesRep, pd.LineTotal AS ResalePrice
        --  FROM dbo.itPurchaseDetails pd
        --  INNER JOIN dbo.itPurchaseHeader ph ON ph.RecID = pd.PurchaseHeaderRecID
        --  INNER JOIN dbo.itVendorLocation vl ON vl.LocationID = ph.VendorLocationID
        --  INNER JOIN dbo.itVendor v ON v.VendorID = vl.VendorID
        --  INNER JOIN dbo.aspnet_custom_UserProfiles cup ON cup.UserID = ph.CreatedBy
        --  WHERE ph.Status > 1 
        --  AND pd.AssetID = a.AssetID
        --) AS do
        LEFT OUTER JOIN FinancialTransactions ft ON ((ft.FinancialTypeID = 9 AND ft.AssetID = a.AssetID) OR (ft.FinancialTypeID = 8 AND ft.FKeyID = a.OrigTransactionID AND ft.AssetID = 0))
        LEFT OUTER JOIN FinancialTransactions ftRec ON ((ftRec.AssetID = a.AssetID) OR (ftRec.FKeyID = a.OrigTransactionID and ftRec.AssetID = 0)) AND ftRec.FinancialTypeID = 1
        --OUTER APPLY 
        --(
        --  SELECT ISNULL(SUM(csa.ServicePriceTotal),0) AS total
        --  FROM ContractServicesApplied csa 
        --  WHERE csa.AssetID = a.AssetID 
        --  AND csa.Completed = 1
        --) AS csa
        --CROSS APPLY(SELECT ISNULL(SUM(T.PartValue),0) AS UpgradeValue
        --FROM dbo.itAssetComponentTransactions AS T
        --INNER JOIN dbo.itAssetComponents AS AC
        --ON AC.RecID = T.AssetComponentID WHERE
        --(T.AssetID = A.AssetId)
        --AND (T.TransactionTypeID = 1) AND (AC.DateRemoved IS NULL)) as uv
        --LEFT JOIN [dbo].[Reporting_Inventory_Harddrives] rih ON a.AssetId = rih.AssetId
        --Tony Added For Recycling Fee Column
        LEFT JOIN (SELECT tp.AssetId, -1*ft.Total AS RecyclingTotal
            FROM itTransactionProcess tp
            INNER JOIN itProcessSteps ps ON tp.NextProcessStepID = ps.ProcessStepID
            LEFT OUTER JOIN FinancialTransactions ft ON ft.FKeyID = tp.TransactionID
            INNER JOIN itLots il on tp.LotNumber = il.LotID
            INNER JOIN AccountLocation al on al.LocationID = il.LocationID
            INNER JOIN Account acc on al.AccountID = acc.accountId
            WHERE acc.AccountID = @AccountId
            AND ps.IsRecyclingProcess = 1
            AND ps.IsEndProcess = 1 ) As Recycling ON a.AssetID = Recycling.AssetID
        --End Recycling Join

        --Tony Added to include Parts section in Asset Detail body of reports
        LEFT JOIN itProcessSteps ps ON tp.NextProcessStepID = ps.ProcessStepID
        --End Parts Join
        --Tony Added for Grade/Condition data
        LEFT OUTER JOIN dbo.itGradeTypes GT ON GT.RecID = a.Grade
        INNER JOIN itAsset ia ON a.AssetID = ia.AssetRecId
        LEFT OUTER JOIN dbo.itGradeTypes GTu ON GTu.RecID = ia.Upgrade_Grade  --Join to asset because vAssetSimpleView does not have upgrade_grade
        --End Grade Join
        OUTER APPLY
        (
            SELECT TOP 1 CASE WHEN ps.IsRecyclingProcess = 1 THEN 'Recycled' WHEN ps.ProcessStepID = 25 THEN 'Resale' ELSE ps.Name END AS Disposition
            FROM itTransactionProcess tp 
            INNER JOIN itProcessSteps ps on ps.ProcessStepID = tp.CurrentProcessStepID 
            WHERE tp.AssetID = a.AssetID 
            AND ps.IsEndProcess = 1
            --AND a.AssetTypeID = 1
        ) AS assetDisp
        WHERE acc.accountid = @AccountId
        AND ((iph_gen.shipDate >= @StartDate AND iph_gen.ShipDate <= @EndDate) OR (a.LockedStatus = 5 AND ftrec.CreatedOn >= @StartDate AND ftrec.CreatedOn <= @EndDate))
        AND ((a.AssetTypeID =1) OR (a.AssetTypeID = 2 and a.ClassID = 919) OR (a.AssetTypeID = 3 and a.ClassID = 919))
         --make sure hard drives are part of the asset report

    LEFT OUTER JOIN FinancialTransactions ftRec ON ((ftRec.AssetID = a.AssetID) OR (ftRec.FKeyID = a.OrigTransactionID and ftRec.AssetID = 0)) AND ftRec.FinancialTypeID = 1
            --OUTER APPLY 

                             After FIX
SELECT DISTINCT


 1 as SourceId,
             l.LotID as 'LotId',
             r.Id as 'RecoveryId',
             acc.AccountName as 'Account',
             r.BillingCode as BillingCode,
             r.ProjectCode as ProjectCode,
             a.AssetID as 'SSE Number',
             ' ' as 'ParentSSENumber',
             COALESCE(ft.InvoiceNumber,Ftrec.InvoiceNumber) as InvoiceNumber,
             COALESCE(ft.InvoicedOn,Ftrec.Invoicedon) as InvoiceDate, 
             a.Class AS Category,
             a.Manufacturer,
             a.Product AS Model, 
             a.ProductNumber AS ModelNum,
             a.SerialNumber AS SerialNum, 
             a.CustomerAssetNumber AS CustAssetTag, 
             a.Weight, 
             @WeightMeasure AS WeightMeasurement,
            CASE a.ClassID --a.LockedStatus 
                WHEN 919
                    THEN CASE hdd.Disposition 
                         WHEN 'Inventory' 
                         THEN
                             CASE  
                             WHEN -ft.Rate > 0 
                                THEN 'Resale'
                                ELSE 'Active' END 
                          ELSE hdd.Disposition END
                ELSE 
                    CASE --ISNULL(A.LockedStatus, - 1) 
                        WHEN A.LockedStatus = -1  THEN 'InProduction' 
                        WHEN A.LockedStatus = 1 THEN 'Active' 
                        WHEN A.LockedStatus = 2 THEN 'On Hold' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 7 THEN 'Redeployment' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 12 THEN 'Donation' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType = 11 THEN 'Legal Hold Release' 
                        WHEN A.LockedStatus = 3 AND iph_gen.PurchaseType NOT IN (7,11,12) THEN 'Sold' 
                        WHEN A.LockedStatus = 4 THEN 'Upgrade' 
                        WHEN A.LockedStatus = 5 THEN 'Recycled' 
                        WHEN A.LockedStatus = 6 THEN 'Sold Off-site' 
                        ELSE '' 
                    END
                 END
                AS Disposition,
            CASE WHEN a.LockedStatus = 5
                 THEN ftRec.CreatedOn
                 ELSE iph_gen.shipDate END AS DispositionDate,               
            '' AS Comments, --REPLACE(r.AdditionalNotes , CHAR(10), '') as Comments,
            isnull(GTu.Name, 'N/A') AS FinalGrade,
              ' ', ' ',
              ISNULL(CASE ftRec.RateTypeID WHEN 1 THEN a.Weight ELSE 1 END * ftRec.Rate,0)  AS RecyclingFees,
            --  ISNULL(ft.RemarketingPercentage,0),
              isnull(ft.Rate,0) AS RemarketingCredit,
              --isnull(gt.Name, 'N/A') AS RegisteredGrade,
              --' ', 
             0.00 as LeaseReturnFee,
             CASE WHEN iph_gen.PurchaseType = 7 THEN ISNULL(ipds_gen.Price,0)
                 ELSE 0.00
                 END AS RedploymentFee,
             CASE WHEN ccsg.GroupName LIKE '%Donation%' THEN
                 CASE WHEN iph_gen.PurchaseType = 12 THEN ISNULL(ipds_gen.Price,0)
                 ELSE 0.00
                 END ELSE 0.00
                 END AS DonationFee
                 --Rank () over
                 --         (
              --              PARTITION by [InviovceDate]
                    --      Order by [SSE Number] DESC
                    --      ) as rank


        FROM vAssetSimpleView a      
        INNER JOIN itTransactionProcess AS tp ON tp.TransactionID = a.OrigTransactionID 
        INNER JOIN itLots AS l ON l.LotID = tp.LotNumber 
        LEFT JOIN [10.10.1.188,13151].Adviser.dbo.Recovery r on l.LotID = r.MRMLotId
        --LEFT JOIN [54.84.218.110,13151].Adviser.dbo.Account acc on r.AccountId = acc.Id
        LEFT OUTER JOIN AccountLocationOrderNo AS alon ON alon.LotID = l.LotID 
        LEFT JOIN AccountLocation AS al ON al.LocationID = l.LocationID 
        LEFT JOIN Account acc ON al.accountId = acc.AccountID
        LEFT JOIN itDocks AS d ON d.DockID = l.DockScheduledOn 
        LEFT OUTER JOIN Contact AS c ON al.Contact_Onsite = c.ContactID 
        LEFT OUTER JOIN itGradeTypes AS g ON g.RecID = a.Grade
        --JOINS FOR ORDERS
        LEFT JOIN itPurchaseDetails ipd_gen on ipd_gen.assetid = a.assetid
        LEFT JOIN itPurchaseDetailService ipds_gen on ipd_gen.RecID = ipds_gen.PurchaseDetailRecId
        LEFT JOIN ContractCustomServiceGroups ccsg on ccsg.recid = ipds_gen.ServiceGroupId
                        --AND ipds_donation.ServiceGroupId IN (SELECT  RecID FROM [ContractCustomServiceGroups]  WHERE GroupName Like '%Donation%')
        LEFT JOIN itPurchaseHeader iph_gen on ipd_gen.PurchaseHeaderRecID = iph_gen.RecID
                        --AND iph_donation.PurchaseType = 12
        --END JOINS FOR ORDERS
        LEFT OUTER JOIN dbo.Reporting_Inventory_Harddrives hdd ON hdd.AssetID = a.AssetID
        --LEFT OUTER JOIN vAssetServicesByType vast ON a.AssetID = vast.AssetRecId
        --OUTER APPLY
        --(
        --  SELECT ph.RecID AS OrderID, v.VendorName, ph.OrderDate,ph.shipdate, cup.FirstName + ' ' + cup.LastName AS SalesRep, pd.LineTotal AS ResalePrice
        --  FROM dbo.itPurchaseDetails pd
        --  INNER JOIN dbo.itPurchaseHeader ph ON ph.RecID = pd.PurchaseHeaderRecID
        --  INNER JOIN dbo.itVendorLocation vl ON vl.LocationID = ph.VendorLocationID
        --  INNER JOIN dbo.itVendor v ON v.VendorID = vl.VendorID
        --  INNER JOIN dbo.aspnet_custom_UserProfiles cup ON cup.UserID = ph.CreatedBy
        --  WHERE ph.Status > 1 
        --  AND pd.AssetID = a.AssetID
        --) AS do
        LEFT OUTER JOIN FinancialTransactions ft ON ft.FinancialTypeID = 9 AND ft.AssetID = a.AssetID  
        LEFT OUTER JOIN   FinancialTransactions ft1 ON ft.FinancialTypeID = 8 AND ft.FKeyID = a.OrigTransactionID AND ft.AssetID = 0 
        LEFT OUTER JOIN FinancialTransactions ftRec ON ftRec.AssetID = a.AssetID 
        LEFT OUTER JOIN  FinancialTransactions ftRec1 ON ftRec.FKeyID = a.OrigTransactionID and ftRec.AssetID = 0  AND ftRec.FinancialTypeID = 1

        --LEFT OUTER JOIN FinancialTransactions ft ON ((ft.FinancialTypeID = 9 AND ft.AssetID = a.AssetID and (ft.FinancialTypeID = 8 AND ft.FKeyID = a.OrigTransactionID AND ft.AssetID = 0))
        --LEFT OUTER JOIN FinancialTransactions ftRec ON ftRec.AssetID = a.AssetID and ftRec.FKeyID = a.OrigTransactionID and ftRec.AssetID = 0 AND ftRec.FinancialTypeID = 1
        --OUTER APPLY 
        --(
        --  SELECT ISNULL(SUM(csa.ServicePriceTotal),0) AS total
        --  FROM ContractServicesApplied csa 
        --  WHERE csa.AssetID = a.AssetID 
        --  AND csa.Completed = 1
        --) AS csa
        --CROSS APPLY(SELECT ISNULL(SUM(T.PartValue),0) AS UpgradeValue
        --FROM dbo.itAssetComponentTransactions AS T
        --INNER JOIN dbo.itAssetComponents AS AC
        --ON AC.RecID = T.AssetComponentID WHERE
        --(T.AssetID = A.AssetId)
        --AND (T.TransactionTypeID = 1) AND (AC.DateRemoved IS NULL)) as uv
        --LEFT JOIN [dbo].[Reporting_Inventory_Harddrives] rih ON a.AssetId = rih.AssetId
        --Tony Added For Recycling Fee Column
        LEFT JOIN  (SELECT  tp.AssetId, -1*ft.Total AS RecyclingTotal
            FROM itTransactionProcess tp
            INNER JOIN itProcessSteps ps ON tp.NextProcessStepID = ps.ProcessStepID
            LEFT OUTER JOIN FinancialTransactions ft ON ft.FKeyID = tp.TransactionID
            INNER JOIN itLots il on tp.LotNumber = il.LotID
            INNER JOIN AccountLocation al on al.LocationID = il.LocationID
            INNER JOIN Account acc on al.AccountID = acc.accountId
            WHERE acc.AccountID = @AccountId 
            AND ps.IsRecyclingProcess = 1
            AND ps.IsEndProcess = 1 ) As Recycling ON a.AssetID = Recycling.AssetID
        --End Recycling Join

        --Tony Added to include Parts section in Asset Detail body of reports
        LEFT JOIN itProcessSteps ps ON tp.NextProcessStepID = ps.ProcessStepID
        --End Parts Join
        --Tony Added for Grade/Condition data
        LEFT OUTER JOIN dbo.itGradeTypes GT ON GT.RecID = a.Grade
        INNER JOIN itAsset ia ON a.AssetID = ia.AssetRecId
        LEFT OUTER JOIN dbo.itGradeTypes GTu ON GTu.RecID = ia.Upgrade_Grade  --Join to asset because vAssetSimpleView does not have upgrade_grade
        --End Grade Join
        OUTER APPLY
        (
            SELECT TOP 1 CASE WHEN ps.IsRecyclingProcess = 1 THEN 'Recycled' WHEN ps.ProcessStepID = 25 THEN 'Resale' ELSE ps.Name END AS Disposition
            FROM itTransactionProcess tp 
            INNER JOIN itProcessSteps ps on ps.ProcessStepID = tp.CurrentProcessStepID 
            WHERE tp.AssetID = a.AssetID 
            AND ps.IsEndProcess = 1
            --AND a.AssetTypeID = 1
        ) AS assetDisp 
        WHERE acc.accountid = @AccountId
        AND ((iph_gen.shipDate >= @StartDate AND iph_gen.ShipDate <= @EndDate) OR (a.LockedStatus = 5 AND ftRec.CreatedOn >= @StartDate AND ftRec.CreatedOn <= @EndDate))
        AND ((a.AssetTypeID =1) OR (a.AssetTypeID = 2 and a.ClassID = 919) OR (a.AssetTypeID = 3 and a.ClassID = 919))  

我知道proc的这一特定部分会降低性能。我希望能够以既能保持高速又能删除多余数据的方式编写这些联接。我试图添加执行计划,但是如果您可以对如何执行该操作有一些见解,那么我将无法执行它们。

1 个答案:

答案 0 :(得分:0)

假设您对ft和ftrec正确,则可以尝试以下操作:

在顶部添加代码:

DROP TABLE IF EXISTS #ftrec

SELECT * 
INTO #ftrec
FROM FinancialTransactions 
where AssetID in (select AssetID from vAssetSimpleView where AssetID is not null)

CREATE CLUSTERED INDEX IX_ftrec on #ftrec(AssetID)

并替换

LEFT OUTER JOIN FinancialTransactions ft ON ft.FinancialTypeID = 9
                                             AND ft.AssetID = a.AssetID


LEFT OUTER JOIN FinancialTransactions ftRec ON ftRec.AssetID = a.AssetID

使用

LEFT OUTER JOIN #ftrec ft ON ft.FinancialTypeID = 9
                                             AND ft.AssetID = a.AssetID

LEFT OUTER JOIN #ftrec ftRec ON ftRec.AssetID = a.AssetID

这假设FinancialTransactions有点小。您可以仅用ftRec实际需要的列替换*。性能影响可能是在初始查询总数#ftrec上。这种解决方案可能是不可行的,如果上FinancialTransactions数据是巨大的。