2012-01-21 12 views
0

私は87の列と53,000の行を持つテーブルtblStkMst2を持っています。次のクエリを実行すると、83〜96ミリ秒(Core2 Duo、2.8 GHz、2 GBのRAM)がかかります。しかし、別のキーワードを使用すると、1086〜1103ミリ秒(1秒以上)がかかります。それは本当に高価です。 53,000行のデータに対して重複除去アルゴリズムを適用すると、1秒かかることはありません。DISTINCTでのSQL Server 2005のパフォーマンスの問題

実行時間を改善するためにSQL Server 2005に他の方法がありますか?

declare @monthOnly int     set @monthOnly = 12 
declare @yearOnly int     set @yearOnly = 2011 

SELECT --(distinct)-- 

tblSModelMst.SMNo as [ModelID] 
,tblSModelMst.Vehicle as [ModelName] 

FROM tblStkMst2 

INNER JOIN tblDCDetail ON tblStkMst2.DCNo = tblDCDetail.DCNo AND tblDCDetail.Refund=0 
INNER JOIN tblSModelMst ON tblStkMst2.SMno = tblSModelMst.SMNo 
INNER JOIN tblBuyerMst ON tblDCDetail.BNo = tblBuyerMst.BNo 
LEFT OUTER JOIN tblSModelSegment ON tblSModelMst.SMSeg = tblSModelSegment.ID 
left outer JOIN dbo.tblProdManager as pd ON pd.PMID = tblBuyerMst.PMId 


WHERE (pd.Active = 1) AND ((tblStkMst2.ISSFlg = 1) or (tblStkMst2.IsBooked = 1)) 
    AND (MONTH(tblStkMst2.SIssDate) = @monthOnly) AND (YEAR(tblStkMst2.SIssDate) = @yearOnly) 
+0

チューニングアドバイザーを使用して見積もり実行計画を表示しようとしましたか。これらは、時間がどこで取られているかを見つけるのに役立ちます。また、主キーと外部キーのすべての列にインデックスがありますか? –

+1

少なくともDISTINCTバージョン、好ましくは両方の実行計画を表示してください。 –

+0

@Abidulイスラム教 - あなたは彼らの継続的な援助をしたい場合は、人々に応答する必要があります。 –

答えて

0

いくつかの方法。

1からDISTINCT

2は使用しないでください - あなたの他のJOINキーをTblSModelMst(SMNo) INCLUDE (Vehicle)にインデックスを作成し、インデックス。

重複が発生した理由をまず理解しておく必要があります。JOIN edテーブルの1つ以上に、一致する行が追加されている可能性があります。

DISTINCTはそれが場所だ持っていますが、多額の不明瞭なデータの問題に使い古さであり、それはあなたがから降りてフィルタリングされた行の数が多い場合は特に、非常に高価な演算子です。

より完全な答えを得るには、データ構造と達成しようとしていることを説明する必要があります。

1

SQL Serverは、ワーストケースの実行を避けるために最適化します。これにより、ハッシュ・ソートよりもディスク・ソートが優先されるような、準最適なアルゴリズムを優先的に使用することができます。

個別の値の数が限られている場合、ハッシュソートはdistinct操作を実行する最も簡単な方法です。ハッシュ・ソートは、実行速度のためにメモリーを交換します。しかし、値が大きい場合は、ハッシュが大きすぎてメモリーに格納できないため、ハッシュ・ソートが失敗します。したがって、ハッシュがメモリに収まるようにSQL Serverに指示する方法が必要です。それは多くの場合、より良いアルゴリズムを選択することができ、

declare @t (ModelID int, ModelName varchar(50)) 
insert @t (ModelID, ModelName) select ...your original query here... 
select distinct ModelID, ModelName from @t 

SQL Serverは一時テーブルのサイズを知っている:それをする

可能な方法の1つは、一時テーブルを使用することです。

+1

これに関する文書はありますか? –

4

DISTINCTは非常に高価です(これはわずか53000行ですが、これは小さいです)。 DISTINCTを追加すると、SQLサーバーは完全に異なるクエリプランを選択しているため、パフォーマンスが大幅に向上しています。クエリプランを見ることなく、何が起きているかを見ることは非常に困難です。

あなたのクエリにはいくつかのことがありますが、パフォーマンスを大幅に向上させる可能性があります。

(1)ここで、あなたが列を変換する必要があり、このような条項は避けてください:あなたはSIssDate列SQL Serverが(それはそうだろう、それを使用することはできませんにインデックスを持っている場合

AND (MONTH(tblStkMst2.SIssDate) = @monthOnly) AND (YEAR(tblStkMst2.SIssDate) = @yearOnly) 

私は他のインデックスを使用することができないと思うので、テーブルのスキャンを行う)。

AND (tblStkMst2.SIssDate between @minDate and @maxDate); 

:あなたはSIssDateインデックスを利用したい場合は、あなたがしようとすると、minとmaxの日付に@ monthOnly/@ yearonlyパラメータを変換し、クエリでこれらを使用する場合

は、それが優れていますあなたがテーブルの上に(クラスタ化インデックスである)代理の主キーを持っている場合は

SELECT @minId=MIN(tblStkMst2_id), @maxId=(tblStkMst2_id) 
FROM 
tblStkMst2 WHERE tblStkMsg2.SIssDate between @minDate and @maxDate; 

これがあるべき、あなたがあなたのクエリ(tblStkMst2_idと呼ばれ、あなたの代理の主キーを想定して)実行する前に、これを行うために有用である可能性があります非常に速いので、SQLサーバーはタを見る必要もないble(SIssDateの非クラスタ化インデックスとtblStkMst2_idクラスタードインデックスのみ)。

次に、あなたが(代わりに日付チェックの)あなたのメインクエリでこれを行うことができます。

AND (tblStkMst2.tblStkMst2_id BETWEEN @minId and @maxId); 

をクラスタ化インデックスを使用してDBを順次ことができるようになりますように、非クラスタ化インデックスを使用するよりもはるかに高速ですこれらのレコードにアクセスします(クラスタ化されていないインデックスのリダイレクトを経由するのではなく)。

(2)DISTINCT(またはGROUP BY)を実行するまで、tblStkMst2への参加を遅延します。 DISTINCT(GROUP BY)のエントリが少なければ少ないほど良いでしょう。

+0

+1 'MONTH()'と 'YEAR()'呼び出しを削除してクエリを変更すると、パフォーマンスに大きな影響を与えます。 –

関連する問題