2016-06-17 5 views
0

私は2つのテーブルを持っています。私はテーブル1のすべての行をテーブル2にあり、それを元に戻したいと思います。私は答えがありましたが、より速くしたいです。 例:最適化 - SQL:すべてのデータを複数のテーブルに表示する方法

Create table One (ID INT, Value INT, location VARCHAR(10)) 
Create table Two (ID INT, Value INT, location VARCHAR(10)) 

INSERT INTO One VALUES(1,2,'Hanoi') 
INSERT INTO One VALUES(2,1,'Hanoi') 
INSERT INTO One VALUES(1,4,'Hanoi') 
INSERT INTO One VALUES(3,5,'Hanoi') 

INSERT INTO Two VALUES(1,5,'Saigon') 
INSERT INTO Two VALUES(4,6,'Saigon') 
INSERT INTO Two VALUES(5,7,'Saigon') 
INSERT INTO Two VALUES(2,8,'Saigon') 
INSERT INTO Two VALUES(2,8,'Saigon') 

と解答:

SELECT * FROM One WHERE ID IN (SELECT ID FROM Two) 
UNION ALL 
SELECT *FROM Two WHERE ID IN (SELECT ID FROM One) 

このクエリでは、システムは、私は、システムが一度テーブル倍(表一をスキャンしたいテーブルを4回 enter image description here

をスキャンし、テーブル2回)。

私はクレイジーですか?

+1

まあ..それは、最初に私はINの代わりにEXISTSに行きます。次に、適切なインデックスを実装します。 – DNac

+1

両方のテーブル間でIDのInner Joinを実行できませんでしたか? – DB101

+0

すみません。私の英語はとても悪いです。 私は質問を修正しました。 –

答えて

0

あなたのような何か試すことができます。

-- CREATE TABLES 
IF OBJECT_ID ('tempdb..#One') IS NOT NULL 
DROP TABLE #One; 

IF OBJECT_ID ('tempdb..#Two') IS NOT NULL 
DROP TABLE #Two; 

CREATE TABLE #One (ID INT, Value INT, location VARCHAR(10)) 
CREATE TABLE #Two (ID INT, Value INT, location VARCHAR(10)) 

-- INSERT DATA 
INSERT INTO #One VALUES(1,2,'Hanoi') 
INSERT INTO #One VALUES(2,1,'Hanoi') 
INSERT INTO #One VALUES(1,4,'Hanoi') 
INSERT INTO #One VALUES(3,5,'Hanoi') 

INSERT INTO #Two VALUES(1,5,'Saigon') 
INSERT INTO #Two VALUES(4,6,'Saigon') 
INSERT INTO #Two VALUES(5,7,'Saigon') 
INSERT INTO #Two VALUES(2,8,'Saigon') 
INSERT INTO #Two VALUES(2,8,'Saigon') 

-- CREATE INDEX 
CREATE NONCLUSTERED INDEX IX_One ON #One (ID) INCLUDE (Value, location) 
CREATE NONCLUSTERED INDEX IX_Two ON #Two (ID) INCLUDE (Value, location) 


-- SELECT DATA 
SELECT o.ID 
     ,o.Value 
     ,o.location 
FROM #One o 
WHERE EXISTS (SELECT 1 FROM #Two t WHERE o.ID = t.ID) 

UNION ALL 

SELECT t.ID 
     ,t.Value 
     ,t.location 
FROM #Two t 
WHERE EXISTS (SELECT 1 FROM #One o WHERE t.ID = o.ID) 

をそれはあなたが持っているどのように「ビッグ」のデータを依存しています。データが本当に大きく(数百万行)、エンタープライズ版のSQL Serverを実行している場合は、columnstore indexesを使用することを検討してください。

+0

ありがとう!私はカラムストアインデックスを勉強します。 –

+0

ColumnStoreのインデックスがここに適用されるかどうかわかりません。おそらく 'ID'フィールドの通常のインデックスで十分です。列ストアは大量のデータを格納するのに適しています(「ほとんどのシステムでは何百万という小さな変更」)が、選択クエリを遅くする副作用があります。この場合、重複のないIDフィールドに大きな穴があると仮定すると、通常のインデックスよりもスキャンスルーに多くの努力が必要になることがあります。さらに、データを変更する必要がある場合、列ストアにはさらに多くのオーバーヘッドがあります。ここで問題になるかもしれないし、そうでないかもしれない何か。私の2セント。 – deroby

0

テーブルを2回スキャンするのは、テーブルXから読み込んでテーブルYの対応する値を検索しているからです。これが終わったら同じことをしますが、テーブルYから始めてその後、両方の結果が結合され、呼び出し側に返されます。

テーブルが「ワイド」であり、必要のない多くの列を含んでいても、正当な理由がないため多くのIOを実行していますが、それは悪いことではありません。さらに、あなたの例では、IDフィールドに「論理」がないので、他のテーブルで一致するIDを探すためにテーブル全体をスキャンする必要があります。これは単に値のリストです。物事をスピードアップするには、IDフィールドにインデックスを追加して、システムが特定のID値をすばやく見つけるのに役立てる必要があります。また、検索フェーズで読み取る必要があるデータの量も制限されます。サーバーは、ID値(**)のみを含む索引から読み取って、他の不要なすべてのフィールドを読み取ることはありません。

ご迷惑をおかけして申し訳ございませんが、ご迷惑をおかけいたしますが、ご了承ください。私の最初の反応は、両方のテーブルの間にJOINを使用することを提案することでしたが、IDフィールドは一意ではないので重複が発生します。その問題を回避するために、DISTINCTを追加しましたが、その後は状況が大幅に遅くなりました。結局のところ、WHERE ID IN (...)を実行することが最も効率的なアプローチであることが判明しました。 IDフィールドにインデックスを追加すると、予想よりも大きな効果はなかったものの、他のフィールドがほとんどなく、IOのゲインが無視できるため読み込み速度が向上しました。 500万行)。

FYI:個人的に私はWHERE IN (...)を超える構成WHERE EXISTS()を好んでいますが、どちらも同等で、実際には全く同じクエリプランが作成されています。

(**:インデックスされたフィールドを除いて、すべてのインデックスには、通常、リーフデータのテーブルフィールドの主キーであるクラスタ化インデックスも含まれます。彼らがどのように働くか)。

関連する問題