SQL Server优化具有子查询的查询

时间:2014-09-10 10:53:04

标签: sql sql-server performance sql-server-2008-r2 sql-server-2012

我使用SQL Server并且查询性能较低。我的查询如下:

Select * 
from ... 
Where exists (Select * From ... Where ...)  

上述查询的执行时间约为8分钟。如果我对此查询使用以下格式,则运行大约3秒。

declare @T table(Columns)
Insert into @T(columns)
Select *
From ...
Where ...

Select *
from ...
Where Exists (Select * From @T)

我不能使用第二种格式,因为我使用Entity Framework并以第一种格式创建查询。我怎么做才能在第一个查询结构中获得高性能。

编辑1 我使用的是Entity Framework 6

此外,我无法使用存储过程,因为我有很多参数,以便在我的应用程序中过滤我的数据。

编辑2 这是实际查询:

SELECT 
    [Project1].[C1] AS [C1], 
    [Project1].[MasterID] AS [MasterID], 
    [Project1].[Date] AS [Date], 
    [Project1].[DateOnly] AS [DateOnly], 
    [Project1].[SalesCompanyFinancialPeriodID] AS [SalesCompanyFinancialPeriodID], 
    [Project1].[Number] AS [Number], 
    [Project1].[Description] AS [Description], 
    [Project1].[FormTypeID] AS [FormTypeID], 
    [Project1].[ProcessTypeID] AS [ProcessTypeID], 
    [Project1].[SalesCompanyID] AS [SalesCompanyID], 
    [Project1].[FinancialPeriodId] AS [FinancialPeriodId], 
    [Project1].[ParentMasterID] AS [ParentMasterID], 
    [Project1].[CustomerID] AS [CustomerID], 
    [Project1].[RecievedDate] AS [RecievedDate], 
    [Project1].[SalesBranchID] AS [SalesBranchID], 
    [Project1].[SellerID] AS [SellerID], 
    [Project1].[IsCompanyIntercourse] AS [IsCompanyIntercourse], 
    [Project1].[C2] AS [C2], 
    [Project1].[C3] AS [C3], 
    [Project1].[C4] AS [C4], 
    [Project1].[C5] AS [C5], 
    [Project1].[C6] AS [C6], 
    [Project1].[C7] AS [C7], 
    [Project1].[C8] AS [C8], 
    [Project1].[C9] AS [C9], 
    [Project1].[C10] AS [C10]
    FROM ( SELECT 
        [Extent1].[MasterID] AS [MasterID], 
        [Extent1].[CustomerID] AS [CustomerID], 
        [Extent1].[RecievedDate] AS [RecievedDate], 
        [Extent1].[SalesBranchID] AS [SalesBranchID], 
        [Extent1].[SellerID] AS [SellerID], 
        [Extent1].[IsCompanyIntercourse] AS [IsCompanyIntercourse], 
        [Extent2].[Date] AS [Date], 
        [Extent2].[DateOnly] AS [DateOnly], 
        [Extent2].[SalesCompanyFinancialPeriodID] AS [SalesCompanyFinancialPeriodID], 
        [Extent2].[Number] AS [Number], 
        [Extent2].[Description] AS [Description], 
        [Extent2].[FormTypeID] AS [FormTypeID], 
        [Extent2].[ProcessTypeID] AS [ProcessTypeID], 
        [Extent2].[SalesCompanyID] AS [SalesCompanyID], 
        [Extent2].[FinancialPeriodId] AS [FinancialPeriodId], 
        [Extent2].[ParentMasterID] AS [ParentMasterID], 
        '0X0X' AS [C1], 
        CAST(NULL AS int) AS [C2], 
        CAST(NULL AS int) AS [C3], 
        CAST(NULL AS int) AS [C4], 
        CAST(NULL AS bit) AS [C5], 
        CAST(NULL AS decimal(18,2)) AS [C6], 
        CAST(NULL AS int) AS [C7], 
        CAST(NULL AS int) AS [C8], 
        CAST(NULL AS int) AS [C9], 
        CAST(NULL AS int) AS [C10], 
        [Extent3].[FinancialPeriodID] AS [FinancialPeriodID1]
        FROM   [SAL].[Invoice] AS [Extent1]
        INNER JOIN [SAM].[Master] AS [Extent2] ON [Extent1].[MasterID] = [Extent2].[MasterID]
        INNER JOIN [ORG].[SalesCompanyFinancialPeriod] AS [Extent3] ON [Extent2].[SalesCompanyFinancialPeriodID] = [Extent3].[SalesCompanyFinancialPeriodID]
    )  AS [Project1]
    WHERE (10 = [Project1].[FinancialPeriodID1]) AND (13852 = [Project1].[SalesCompanyID]) AND ([Project1].[DateOnly] <= convert(datetime2, '2014-09-09 00:00:00.0000000', 121)) AND (convert(datetime2, '2014-09-07 00:00:00.0000000', 121) <=  CAST(  CAST( [Project1].[DateOnly] AS datetime2) AS datetime2)) AND (13852 = [Project1].[SalesCompanyID]) 
    AND ( EXISTS (SELECT 
        1 AS [C1]
        FROM   (SELECT [Extent4].[OrderMasterID] AS [OrderMasterID], [Extent5].[MasterID] AS [MasterID1]
            FROM        [SAL].[InvoiceDetail] AS [Extent4]
            INNER JOIN [SAM].[Detail] AS [Extent5] ON [Extent4].[DetailID] = [Extent5].[DetailID]
            LEFT OUTER JOIN [SAL].[Order] AS [Extent6] ON [Extent4].[OrderMasterID] = [Extent6].[MasterID]
            LEFT OUTER JOIN [SAL].[SalesBranch] AS [Extent7] ON [Extent6].[SalesBranchID] = [Extent7].[SalesBranchID]
            INNER JOIN [SAL].[SalesBranch] AS [Extent8] ON [Extent6].[SalesBranchID] = [Extent8].[SalesBranchID]
            LEFT OUTER JOIN [SAL].[Order] AS [Extent9] ON [Extent4].[OrderMasterID] = [Extent9].[MasterID]
            INNER JOIN [SAL].[Order] AS [Extent10] ON [Extent4].[OrderMasterID] = [Extent10].[MasterID]
            LEFT OUTER JOIN [SAL].[Order] AS [Extent11] ON [Extent4].[OrderMasterID] = [Extent11].[MasterID]
            WHERE ([Extent7].[SalesScopeID] IN (43893, 43900)) AND ([Extent8].[SalesScopeID] IS NOT NULL) AND ([Extent9].[SalesBranchID] IN (77017, 43063, 43029, 43021)) AND ([Extent10].[SalesBranchID] IS NOT NULL) AND ([Extent11].[SellerID] IN (42768, 50552, 15904, 15090, 15717, 16063, 43109, 43110, 43113, 43114, 43118, 43120, 43121, 43123, 43124, 43125, 43126, 43127, 43129, 43130, 43131, 43132, 43133, 43134, 43136, 43137, 43138, 43141, 43147, 43152, 43153, 43154, 43160, 43168, 43178, 43179, 43184, 43185, 43186, 43187, 43189, 43209, 43211, 43215, 43218, 43223, 43235, 43242, 43248, 43249, 43250, 43251, 43252, 43261, 43269, 43278, 43283, 43298, 43308, 43313, 43316, 43325, 43328, 43329, 43337, 43356, 43360, 43384, 43385, 43394, 43400, 43415, 43418, 43424, 43425, 43428, 43434, 43441, 43518, 43532, 43546, 43548, 43549, 44359, 44368, 44490, 47035, 48849, 49139, 49140, 49153, 49156, 50212, 50422, 50423, 51023, 52158, 61908, 61909, 79146, 80261, 80466, 80734, 80735, 80983, 82822, 86309, 86436, 86578, 86825, 86879, 87120, 43149, 45166, 44366, 80233)) ) AS [Filter1]
        INNER JOIN [SAL].[Order] AS [Extent12] ON [Filter1].[OrderMasterID] = [Extent12].[MasterID]
        WHERE ([Extent12].[SellerID] IS NOT NULL) AND ([Project1].[MasterID] = [Filter1].[MasterID1])
    )) AND ([Project1].[FormTypeID] = 6) AND (6 IS NOT NULL)

编辑3:这是我的查询的执行计划:

enter image description here

2 个答案:

答案 0 :(得分:0)

我不是SQL大师,但我认为这是一个非常糟糕的习惯,有子查询;你应该避免这种情况。

例如,您可以先执行2个子查询,然后在程序中动态构建最终的SQL查询。或者在表上放置一些触发器以准备查询数据(创建一个易于查询的额外表)。

答案 1 :(得分:0)

如果检查丢失的索引,您可能会在实际查询中获得更好的性能。您可以尝试在SQL Management Studio中运行它并使用显示估计执行计划,这将显示您是否可能缺少链接表上的索引,如果它然后通过单击消息您可以生成SQL代码来创建索引。否则我认为我们可能需要查看您用来生成所述代码的LINQ语句。