2017-02-20 82 views
0

この質問の重要な部分は、「最適に」は最速の戻り時間を意味します。私はいくつかのテーブルを持っています。私は、情報を得る最速の方法が何であるかを判断しようとしているだけで、クエリ自体を書くのに何の問題もありません。複数のテーブルからレコードを最適に取得する方法

  • 監査(これは私がからの情報が欲しい主テーブルである)
  • 注文(残りは私がからの限られたデータをするテーブルです)
  • ジョブズ
  • クレジット

事彼ら共通の共有はアカウントであり、従ってAccountIDである。私は前もって探していたAccountIDを持っています。残念なことに、監査テーブルは、問題のアカウントテーブルに直接外部キーを持たないため、監査レコードが私の結果セットに属しているかどうかを判断するために、監査テーブルとその後の3つのテーブルに一度に1つずつ参加する必要があります監査レコードが自分のAccountIDに関連しているかどうかを確認します。

は例

Select a.* from [Audits] a JOIN [Orders] o ON a.RecordID = o.OrderID 
where a.RecordType = 'Order' and o.AccountID = @AccountID 
union 
select a.* from [Audits] a JOIN [Jobs] j on a.RecordID = j.JobID 
where a.RecordType = 'Job' and j.AccountID = @AccountID 
... 

のために私は、データの第1のサブセットに次のフェッチと私が最初に制限されたヒットをやっているように、二次テーブルからの情報を記入するつもり。私はこれを2つの部分の問題として見ています。まず、私のサブセットに属するAuditIDを見つける最速の方法と、欠落したデータを埋めるための最速の方法です。任意の提案をいただければ幸いです。ので、私はここに投稿するつもりです私は今のソリューションを作ってみたが、それを最適化する任意の簡単な方法があるかどうか、私は知ることに興味があると思い

EDIT 1

問題をさらに明確にするのに役立つと考えています。構文エラーが発生した場合は無視してください。できるだけ多くの不要な情報を削除しようとしています。

私が必要とする20個のレコードを取得し、一致すると同時に1つずつ入力します。

+0

「Audit」テーブルの「RecordID」フィールドは、Order、Job、またはCreditのいずれかになります。彼らが共有する唯一のものは「AccountID」フィールドです。 –

+1

それは見た目...楽しいです。頭に浮かぶことは、 'union'の代わりに' union all'を使うことです。それは 'union'から余分な並べ替えと重複をスキップします。 – SqlZim

+0

使用しているSQL Serverのバージョンとエディションは何ですか? 'select @@ version' – SqlZim

答えて

1

これが常時行う必要がある場合は、セカンダリテーブルからviewを作成し、それを使用してAuditテーブルをセカンダリテーブルと結合します。

CreateView [dbo].[SecondaryTables] 
AS 
SELECT OrderID AS RecordID, 'Order' AS RecordType, AccountID 
FROM [Orders] 
UNION 
SELECT JobID AS RecordID, 'Job' AS RecordType, AccountID 
FROM [Jobs] 
UNION 
SELECT CreditID AS RecordID, 'Credit' AS RecordType, AccountID 
FROM [Credits] 

その後、あなたは、あなたがすべてのテーブル(すべての結果は、常に3つのテーブルからのデータが含まれます)からの結果を期待する場合は、

SELECT [all your required fields] 
FROM [SecondaryTables] vw 
INNER JOIN [Audit] au 
ON vw.RecordID = au.RecordID AND vw.RecordType = au.RecordType 
LEFT OUTER JOIN [Orders] od 
ON vw.RecordID = od.OrderID AND vw.RecordType = 'Order' 
LEFT OUTER JOIN [Jobs] jo 
ON vw.RecordID = jo.JobID AND vw.RecordType = 'Job' 
LEFT OUTER JOIN [Credits] cr 
ON vw.RecordID = cr.CreditID AND vw.RecordType = 'Credit' 
WHERE vw.AccountID = @AccountID 

を必要とするすべてのデータを結合するために、このビューを使用することができますパフォーマンスを向上させるためにLEFT OUTERINNERに変更できます。

1

最初に行うことは、クエリの実行計画を見ることです。可能な選択肢は以下の通りです。

SELECT A.* 
FROM [Audits] A 

INNER JOIN (
    SELECT OrderID AS RecordID FROM [Orders] WHERE AccountID = @AccountID 
    UNION ALL 
    SELECT JobID AS RecordID FROM [Jobs] WHERE AccountID = @AccountID 
) AS DT 
ON A.RecordID = DT.RecordID 
WHERE A.RecordType IN ('Order','Job') 

もう1つの方法は、UNION ALLクエリを共通テーブル式にシフトすることです。

最近、SQL Serverオプティマイザはかなり良い状態です。最低限必要なクエリを見つけるのは簡単ですが、それは最速のものと全く同じではありません。

通常、アカウントの注文や仕事が非常に少ない場合は、元のように2回ではなく1回だけ参加することになります。

[監査]テーブルのRecordTypeの選択性を考慮してください。オーダーとジョブが大部分のレコードで構成されている場合、RecordTypeに対する索引を追加することはほとんど効果がありません。おそらく、OrderとJobsにAccountIDに対するインデックスがありますか?

テーブルのスキーマを明示的に指定することを検討してください。 dbo.Audits、Sales.ordersなど。実行時に照会エンジンが比較する必要があるのは1つ少ないことです。

SQL Serverのパフォーマンステストは、共有環境では少し苦労する可能性があります。私は、SQLプロファイラを使用して私のクエリとその時に実行されているものの両方のために起こっているものとして良い指標を見つけると、それはあなたに必要なすべてのタイミングを与えるでしょう。

サーバーが停止しているときにテストする場合は、実行ごとにDBCC DROPCLEANBUFFERSによってバッファキャッシュがフラッシュされることを覚えておいてください。クエリが寒いからどのように実行されるかについて明確なビューを得ることができます。

プロダクションボックスがテストボックスと異なる仕様であれば、何も隠れています。大量のRAMと共有ストレージを備えたマルチコアサーバは、特に複数のタスクを同時に実行している場合は、典型的なDEVワークステーションとは異なる動作をします。

関連する問題