3

パフォーマンスに関して、左結合と内部結合に違いはありますか? SQL Server 2012 を使用しています。

4

2 に答える 2

11

LEFT [OUTER] JOINがよりも優れたオプションであるケースが少なくとも 1 つあります[INNER] JOINOUTERの代わりに を使用して同じ結果を得ることについて話しINNERます。

例 ( AdventureWorks 2008 データベースを使用しています):

-- Some metadata infos
SELECT  fk.is_not_trusted,  fk.name
FROM    sys.foreign_keys fk
WHERE   fk.parent_object_id=object_id('Sales.SalesOrderDetail');
GO

CREATE VIEW View1
AS 
SELECT  h.OrderDate, d.SalesOrderDetailID, o.ModifiedDate
FROM    Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
INNER JOIN Sales.SpecialOfferProduct o ON d.SpecialOfferID=o.SpecialOfferID AND d.ProductID=o.ProductID;
GO

CREATE VIEW View2
AS
SELECT  h.OrderDate, d.SalesOrderDetailID, o.ModifiedDate
FROM    Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON d.SalesOrderID = h.SalesOrderID
LEFT JOIN Sales.SpecialOfferProduct o ON d.SpecialOfferID=o.SpecialOfferID AND d.ProductID=o.ProductID;
GO

SELECT  SalesOrderDetailID
FROM    View1;

SELECT  SalesOrderDetailID
FROM    View2;

最初のクエリの結果:

is_not_trusted name
-------------- ---------------------------------------------------------------
0              FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID
0              FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID

最後の 2 つのクエリの実行計画: ここに画像の説明を入力

注 1 / ビュー 1:の実行計画SELECT SalesOrderDetailID FROM View1 を見ると、制約が信頼されており、列が 1 つしかないため、FK が削除されていることがわかります。ただし、句にこのテーブルの列が含まれておらず、FK 制約 (FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID) が (また) 信頼されていてもFK_SalesOrderDetail_SalesOrderHeader_SalesOrderID、サーバーは (理由によりINNER JOIN Sales.SpecialOfferProduct) 3 番目のテーブル (SpecialOfferProduct) からデータを読み取ることを強制されます。SELECT/WHEREこれは、この最後の FK が複数列であるために発生します。

注 2 / ビュー 2:Scanの読み取り ( / Seek)を削除したい場合はどうすればよいSales.SpecialOfferProductですか? この 2 番目の FK は複数列であり、そのような場合、SQL Server は FK を削除できません (以前の Conor Cunnigham のブログ記事を参照してください)。この場合、FK を除去するために をINNER JOIN Sales.SpecialOfferProductに置き換える必要があります。列と列のLEFT OUTER JOIN Sales.SpecialOfferProduct両方があり、信頼できる FK 参照テーブルがあります。SpecialOfferIDProductIDNOT NULLSpecialOfferProduct

于 2013-02-24T10:06:57.813 に答える
7

追加の行が保持されるために外部結合がより大きな結果セットを返す可能性があるという問題と同様に、もう1つのポイントは、INNER JOIN可換で連想的であるため、オプティマイザーが実行プランを作成する際の可能性が広がることです。

したがって、次の例Bではインデックスが付けられていますが、そうでAはありません。

CREATE TABLE A(X INT, Filler CHAR(8000))

INSERT INTO A 
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY @@SPID), ''
FROM sys.all_columns

CREATE TABLE B(X INT PRIMARY KEY, Filler CHAR(8000))

INSERT INTO B
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY @@SPID), ''
FROM sys.all_columns

SELECT *
FROM B INNER JOIN A ON A.X = B.X

SELECT *
FROM B LEFT JOIN A ON A.X = B.X

オプティマイザーはそれを認識してB INNER JOIN Aおり A INNER JOIN B、同じであり、テーブルをシークするネストされたループを含むプランを作成しますB

予定

この変換は外部結合には無効であり、ネストされたループは右外部結合ではなく左外部結合のみをサポートするため、別の結合タイプを使用する必要があります。

ただし、実用的な観点からは、正しいセマンティクスを提供する必要な結合タイプを選択する必要があります。

于 2013-02-24T10:01:04.823 に答える