0

私のデータベースはSQLServer2005DBに保存されています。

このクエリの実行には1秒もかかりません。

SELECT * FROM ( 

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid

) as x
where RowNum >=  21001 and RowNum <  21011

このクエリの実行には10秒かかります。

SELECT * FROM ( 

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
OrderDate
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, tblOrders.OrderDate

) as x
where RowNum >=  21001 and RowNum <  21011

なぜそのような違いがあるのでしょうか?

すべてのテーブルには、主キーを保持するidという列があります。データベースを設計しなかったので、orderidとProductIdが存在する理由がわかりません。

/バリー

アップデート

OrderDateは日時です

2回目の更新

3つのテーブルにはそれぞれ、主キーとして機能するid列があることを忘れないでください。ただし、テーブル間を参照する場合は、orderid、productidなどが使用されます。なぜこのように実装されたのかはわかりませんが、非常に間違っていると思います。

tblOrders:
Id; int; no null; PK
OrderId; int; allow null
OrderDate; datetime; allow null

tblOrderDetails:
Id; int; no null; PK
OrderId; int; allow null
ProductId; int; allow null

tblProducts:
Id; int; PK; no null
ProductId; allow null
Price; money; allow null

これはクエリ実行プランに関して適切ですか?-

ここに画像の説明を入力してください

3番目の更新

これは実行に1秒しかかかりません-

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
OrderDate
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, OrderDate

そしてこれはたった2秒-

SELECT * FROM (
  SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,
  SUM(tblProducts.Price) as price,
  MAX(tblOrders.OrderDate) as OrderDate  -- do this instead of grouping
FROM tblOrders
  LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId
  LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid  ) as x

しかし、これには10秒かかります-

SELECT * FROM (
  SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,
  SUM(tblProducts.Price) as price,
  MAX(tblOrders.OrderDate) as OrderDate  -- do this instead of grouping
FROM tblOrders
  LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId
  LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid  ) as x
where RowNum >=  21001 and RowNum <  21011

where句は8秒を追加しています。なんで?

4

4 に答える 4

2

出力リストとグループ化句の両方に「tblOrders.OrderDate」を含めると速度が低下するというドーナツに賭けます。SET STATISTICS IO ON2 つのクエリを実行して、各テーブルで異なるスキャンとシークを取得する方法を確認することをお勧めします。

SQL エンジンは、OrderDate 列を考慮した 2 番目のクエリに対して劇的に異なる計画を持っている可能性が非常に高く、その結果、CPU 処理が増えるか、(可能性が高い) 多くのディスク IO が発生します。

于 2012-04-15T21:26:23.943 に答える
0

注文日とは何ですか? 日付時刻?これらのクエリは非常によく似ていますが、OrderDate には時間情報が含まれていると思われるため、並べ替えとグループ化ははるかにコストがかかります (そして、2 番目のクエリのサブクエリでより多くの行が発生します)。

次の変更を検討してください。

SELECT RowNum, price, DD = DATEADD(DAY, DD, '19000101') FROM (     
SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
DATEDIFF(DAY, '19000101', tblOrders.OrderDate) as DD
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, DATEDIFF(DAY, '19000101', tblOrders.OrderDate)

) as x
where RowNum >=  21001 and RowNum <  21011
ORDER BY RowNum;

SQL Server 2008以降では、それを単純化できますCONVERT(DATE, OrderDate)...

于 2012-04-15T23:04:42.760 に答える
0

実際のテーブル構造と実行計画がなければ正確に答えることはできませんが、 orderid が tblOrders で一意である場合は、 group by ステートメントから OrderDate を削除し、 select リストに as として追加することをお勧めしますmin(tblOrders.OrderDate) as OrderDate。同じ結果が得られるはずです (tblOrders.orderid が一意のキーの場合) が、はるかにうまく機能します。

于 2012-04-16T09:36:26.383 に答える
0

これは実行計画なしでは答えられませんが、私は推測できます:

  • 追加の列がインデックスの使用を妨げている可能性があります
  • 遅いクエリのカーディナリティが非常に高い
  • OrderDate の統計が何らかの理由で古くなっています (exec sp_updatestats)

更新: あなたが投稿した実行計画は実に恐ろしいものです。

インデックスを作成します。

create unique nonclustered index x0 on tblOrder(orderid) include (OrderDate)
create unique nonclustered index x1 on tblProduct (productid) include (Price)
create nonclustered index x2 on tblOrderDetails(orderid, ProductId)
于 2012-04-15T21:11:48.927 に答える