查询视图时响应缓慢 - 使用Linq to SQL

时间:2010-01-08 13:17:24

标签: sql linq-to-sql sql-view

我有以下观点:

SELECT     
poHeader.No_ AS PONumber, 
poHeader.[Buy-from Vendor No_] AS VendorNumber, 
poHeader.[Document Date] AS DocumentDate, 
vendor.Name AS VendorName, 
vendor.Contact AS VendorContact, 
vendor.[E-Mail] AS VendorEmail, 
vendor.Address AS VendorAddress, 
vendor.[Address 2] AS VendorAddress2, 
vendor.City AS VendorCity, 
vendor.County AS VendorCounty, 
vendor.[Post Code] AS VendorPostCode, 
vendor.[Phone No_] AS VendorPhone, 
vendor.[Fax No_] AS VendorFax, 
salesHeader.No_ AS SONumber, 
poHeader.[Order Date] AS OrderDate, 
salesHeader.[Crocus Comment] AS CrocusComment, 
salesHeader.GiftMessage, 
salesHeader.[Delivery Comment] AS DeliveryComment, 
salesHeader.[Shipment Date] AS DeliveryDate, 
COALESCE (salesHeader.[Ship-to Name], 
poHeader.[Ship-to Name]) AS DeliveryName, 
COALESCE (salesHeader.[Ship-to Address],
poHeader.[Ship-to Address]) AS DeliveryAddress, 
COALESCE (salesHeader.[Ship-to Address 2],
poHeader.[Ship-to Address 2]) AS DeliveryAddress2,
COALESCE (salesHeader.[Ship-to City], 
poHeader.[Ship-to City]) AS DeliveryCity, COALESCE (salesHeader.[Ship-to County], 
poHeader.[Ship-to County]) AS DeliveryCounty, 
COALESCE (salesHeader.[Ship-to Post Code], 
poHeader.[Ship-to Post Code]) AS DeliveryPostcode, 
salesHeader.DeliveryPhoneNo, poForEmailing.Processed, 
poForEmailing.Copied

FROM         
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
INNER JOIN
Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

此视图在名为NavisionMeta的数据库中创建 它查询一个数据库(在同一台服务器上)claled Navision4

我最近将两个数据库都移到了新的(更好的)硬件上。 不确定这是否相关,但新硬件有SQL 2008,旧硬件运行SQL 2000

如果我在SQL Management Studio中使用此查询查询它,则需要2分钟以上:

SELECT * 
FROM [NavisionMeta].[dbo].[PurchaseOrders]
WHERE Processed=0 AND Copied=0

太长时间了!

即使我将超时调整为5分钟,LINQ中的以下查询也会一起超时!

            var purchaseOrdersNotProcessed = (from p in db.PurchaseOrders
                                              where p.Copied.Equals(0)
                                              && p.Processed.Equals(0)
                                              select p).ToList();

让我感到困惑的是,在之前的硬件上,它运行良好!

以防它是相关的,上面使用的udf是:

CREATE FUNCTION [dbo].[fnGetSalesOrderNumber](@PONumber varchar(20))
RETURNS varchar(20)
AS
BEGIN

RETURN (
SELECT 
    TOP 1 [Sales Order No_]
FROM 
    Navision4.dbo.[Crocus Live$Purchase Line]
WHERE 
    [Document No_] = @PONumber
)

4 个答案:

答案 0 :(得分:1)

您也可以考虑更新统计信息。

答案 1 :(得分:1)

左内加入?嗯,不确定这是否会有所帮助......

如果此查询之前有效(数据不是性能),则上述查询将从将所有连接转换为INNER JOIN中受益。因为你是来自poHeader(外连接)的值的INNER JOINing供应商,所以你基本上也在poHeader上建立了一个内连接要求(除了外连接的潜在性能命中)。除非poHeader具有值,并且供应商是内连接的,否则供应商不能返回值,如果poHeader中没有值,则将忽略整行。与salesHeader相同。连接中使用的函数需要poHeader中的值(必须具有根据上述逻辑的值),因此此连接也可以从显式的INNER JOIN中获益,而不仅仅是隐含的连接。

除此之外,我同意关于索引的陈述(除了关于外连接的陈述很少。这就像说如果你有锤子你不需要螺丝刀)。索引听起来像是对性能较弱的最合乎逻辑的解释。具体来说,您应该检查poForEmailing别名表是否有索引([processed],[copied])。如果没有该索引,您可以期望查询时间至少加倍,因为数据大小加倍,因为该表中的每个记录都需要针对这些谓词进行测试。关于你原来的问题,我没有注意到SQL Server 2008中任何表明性能发生这种变化的东西,其他条件都相同。

答案 2 :(得分:0)

一个起点可能是在旧机器和新机器上查看查询的执行计划。对于较新版本的SQL Server,肯定存在优化差异。执行计划可能会向您显示索引是必要的,由于某种原因,索引在先前版本中并不那么重要。

答案 3 :(得分:0)

修改

我不确定你要做什么,但如果你想获得有关PO的信息,我认为下面的更改会有所帮助,你有

FROM Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
  LEFT OUTER JOIN Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
  INNER JOIN Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
  LEFT OUTER JOIN Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

试试这个:

FROM Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
  LEFT JOIN Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
  LEFT JOIN Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
  LEFT JOIN Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

就速度而言,您可能需要更新一些索引...尤其是No_字段。 另外进行以下更改以消除每行调用的fuGetSalesOrderNumber():

;WITH PurchaseLineByPO AS
(
  SELECT MAX([Sales Order No_]) as SO, [Document No_] as DNum
  FROM Navision4.dbo.[Crocus Live$Purchase Line]
  Group By [Document No_]
)
--blah blah whole select goes here.. with
JOIN PurchaseLineByPO ON DNum = poHeader.No_
--in the join and 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = PurchaseLineByPO.SO
--replaces what you had

看看它是否适合你。

忽略下面的旧内容......

我很难确切地看到你在这里做了什么,但是很少需要OUTER连接 - 这实际上是你想做什么的?如果是,您可以撤消订单并进行内部联接。例如,你说:

FROM         
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 

你可以说

FROM         
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader 
LEFT INNER JOIN
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing ON poForEmailing.No_ = poHeader.No_ 

根据您的数据,这可能会对您的运行时间产生重大影响。