1. ホーム
  2. sql

[解決済み】SQL ServerにおけるINNER JOINとLEFT JOINのパフォーマンス比較

2022-03-31 16:16:34

質問

9つのテーブルに対してINNER JOINを使用するSQLコマンドを作成しましたが、このコマンドには非常に長い時間(5分以上)がかかります。そこで、私の部下がINNER JOINをLEFT JOINに変更することを勧めました。私が知っているにもかかわらず、LEFT JOINのパフォーマンスがより良いからです。私はそれを変更した後、クエリの速度が大幅に改善されました。

なぜLEFT JOINの方がINNER JOINより速いのか知りたいのですが?

私のSQLコマンドは以下のようなものです。 SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN D といった具合に

更新してください。 これは私のスキーマの概要です。

FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
    INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
        ON a.CompanyCd = b.CompanyCd 
           AND a.SPRNo = b.SPRNo 
           AND a.SuffixNo = b.SuffixNo 
           AND a.dnno = b.dnno
    INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
        ON a.CompanyCd = h.CompanyCd
           AND a.sprno = h.AcctSPRNo
    INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
        ON c.CompanyCd = h.CompanyCd
           AND c.FSlipNo = h.FSlipNo 
           AND c.FSlipSuffix = h.FSlipSuffix 
    INNER JOIN coMappingExpParty d -- NO PK AND FK
        ON c.CompanyCd = d.CompanyCd
           AND c.CountryCd = d.CountryCd 
    INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
        ON b.CompanyCd = e.CompanyCd
           AND b.ProductSalesCd = e.ProductSalesCd 
    LEFT JOIN coUOM i -- PK = UOMId
        ON h.UOMId = i.UOMId 
    INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
        ON a.CompanyCd = j.CompanyCd
            AND b.BFStatus = j.BFStatus
            AND b.ProductSalesCd = j.ProductSalesCd
    INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
        ON e.ProductGroup1Cd  = g1.ProductGroup1Cd
    INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
        ON e.ProductGroup1Cd  = g2.ProductGroup1Cd

解決方法は?

A LEFT JOIN よりも絶対に速くありません。 INNER JOIN . 実際、より遅いです。定義によれば、外部結合( LEFT JOIN または RIGHT JOIN のすべての作業を行わなければなりません。 INNER JOIN さらに、結果をヌル拡張する余分な作業もあります。 また、より多くの行を返すことが予想され、結果セットのサイズが大きくなるため、単純に実行時間の合計がさらに増加します。

(また、仮に LEFT JOIN だった で速くなった。 特定 とは機能的に同等ではありません。 INNER JOIN そのため、単純に一方のインスタンスをすべて他方のインスタンスに置き換えることはできません!)

ほとんどの場合、パフォーマンスの問題は、候補キーまたは外部キーが適切にインデックスされていないなど、他の場所にあります。 9つのテーブルを結合するのは非常に多いので、速度低下の原因は文字通りほとんどどこにでもあり得ます。 スキーマを投稿していただければ、より詳細な情報を提供できるかもしれません。


編集する

このことをさらに振り返ると、ある状況下で LEFT JOIN よりも速いかもしれません。 INNER JOIN というときです。

  • 一部のテーブルは 大変 小さい(例えば、10行以下)。
  • テーブルには、クエリをカバーするのに十分なインデックスがありません。

この例で考えてみましょう。

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

これを実行して実行プランを表示すると INNER JOIN クエリの方が LEFT JOIN というのは、上記の2つの条件を満たしているからです。 それは、SQL Server が INNER JOIN に対してネストされたループを実行します。 LEFT JOIN 前者は 通常 よりもはるかに高速ですが、行数が非常に少ないため インデックスを使用しないため、ハッシュ処理がクエリの中で最も高価な部分となります。

好きなプログラミング言語で、5つの要素を持つリストと5つの要素を持つハッシュテーブルを大量に検索するプログラムを書けば、同じ効果を確認することができます。 サイズが小さいので、実際にはハッシュテーブルの方が遅くなります。 しかし、50要素、5000要素と増やすと、ハッシュテーブルのO(1)に対し、リストのO(N)となり、遅くなるのである。

しかし、このクエリを ID カラムではなく Name をクリックすると、まったく違うことがわかります。 この場合、両方のクエリでネストされたループが行われます。 INNER JOIN バージョンでは、クラスタ化されたインデックススキャンのひとつをシークに置き換えることができるため、文字通り 桁違いの 行数が多い場合、より高速になります。

つまり、結論としては、ほぼ間違いなくインデックスまたはインデックスカバレッジの問題で、おそらく1つまたは複数の非常に小さなテーブルと組み合わさっているのです。 このような状況でSQL Server 可能性があります。 に対して、より悪い実行計画を選択することがあります。 INNER JOIN よりも LEFT JOIN .