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

左内結合? うーん、それがまったく役立つかどうかはわかりません...

このクエリが以前に機能していた場合 (パフォーマンスではなくデータ)、上記のクエリは、すべての結合を INNER JOIN に変換することでメリットが得られます。あなたは poHeader (外部結合) からの値に対して INNER JOINing ベンダーであるため、本質的に poHeader にも内部結合要件を作成しました (外部結合の潜在的なパフォーマンス ヒットを除く)。poHeader に値がない限り、ベンダーは値を返すことができず、ベンダーは内部結合されているため、poHeader に値がない場合は行全体が無視されます。salesHeader と同じです。結合で使用される関数には、poHeader の値が必要です (上記のロジックに従って値が必要です)。そのため、この結合は、暗黙の JOIN ではなく、明示的な INNER JOIN にすることでもメリットがあります。

それ以外は、インデックスに関する記述に同意します (外部結合がほとんど必要ないことを除いて。それは、ハンマーがあればドライバーは必要ないと言っているようなものです)。インデックス作成は、パフォーマンスの低下の最も論理的な説明のように思えます。具体的には、poForEmailing エイリアス テーブルに ([処理済み],[コピー済み]) のインデックスがあるかどうかを確認する必要があります。そのインデックスがないと、データ サイズが 2 倍になるため、クエリ時間が少なくとも 2 倍になることが予想されます。これは、そのテーブル内のすべてのレコードをこれらの述語に対してテストする必要があるためです。あなたの最初の質問に関して、私は SQL Server 2008 でパフォーマンスのこのような変化を示唆するものに気づいていません。他のすべてのことは同じです。

于 2010-03-09T02:36:30.250 に答える
1

また、統計の更新を検討することもできます。

于 2010-01-08T19:56:27.440 に答える
0

出発点として、古いマシンと新しいマシンの両方でクエリの実行計画を確認することをお勧めします。新しいバージョンの SQL Server では最適化の違いが確実にあります。実行計画では、何らかの理由で以前のバージョンではそれほど重要ではなかったインデックスが必要であることが示される場合があります。

于 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 に答える