0

我有以下看法:

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 的数据库中创建的,它查询一个名为 Navision4 的数据库(在同一台服务器上)

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

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

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

这太长了!

LINQ 中的以下查询全部超时,即使我将超时时间调整为 5 分钟!

            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

4 回答 4

1

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

于 2010-01-08T19:56:27.440 回答
1

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

如果此查询以前有效(数据不是性能),那么上面的查询将受益于将所有联接转换为 INNER JOIN。因为您是来自 poHeader 的值的 INNER JOINing 供应商(它是外连接的),所以您基本上也对 poHeader 提出了内连接要求(除了外连接的潜在性能影响)。Vendor 不能返回值,除非 poHeader 有值,并且由于 vendor 是内部连接的,如果 poHeader 中没有值,则将忽略整行。与 salesHeader 相同。连接中使用的函数需要 poHeader 中的值(根据上述逻辑必须有一个值),所以这个连接也将受益于被制作成显式的 INNER JOIN 而不是隐含的。

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

于 2010-03-09T02:36:30.250 回答
0

A starting point might be to look at the execution plan for the query on both the old machine and the new machine. There will certainly be optimization differences with newer versions of SQL Server. The execution plan might show you that an index is necessary that, for some reason, was not as critical in the previous version.

于 2010-01-08T13:32:08.880 回答
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_ 

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

于 2010-01-08T20:51:02.723 回答