sql >> データベース >  >> RDS >> Sqlserver

ID が 2 番目のテーブルに存在する行を選択する最も効率的な方法

    まとめ:

    以下のテスト データ セットを使用して、各クエリをそれぞれ 10 回実行しました。

    <オール>
  1. 非常に大きなサブクエリの結果セット (100000 行)
  2. 重複する行
  3. 空行
  4. 上記のすべてのシナリオで、両方の IN そしてEXISTS

    Performance V3 データベース に関する情報 テストに使用されます。20000 人の顧客が 1000000 の注文を持っているため、各顧客は注文テーブルで (10 から 100 の範囲で) ランダムに複製されます。

    実行コスト、時間:
    以下は、実行中の両方のクエリのスクリーンショットです。各クエリの相対コストを観察します。

    メモリ コスト:
    2 つのクエリのメモリ許可も同じです..TEMPDB に流出しないように MDOP 1 を強制しました..

    CPU 時間、読み取り:

    存在する場合:

    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Customers'. Scan count 1, logical reads 109, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Orders'. Scan count 1, logical reads 3855, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
    (1 row(s) affected)
    
     SQL Server Execution Times:
       CPU time = 469 ms,  elapsed time = 595 ms.
    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 0 ms.
    

    インの場合:

    (20000 row(s) affected)
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Customers'. Scan count 1, logical reads 109, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Orders'. Scan count 1, logical reads 3855, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
    (1 row(s) affected)
    
     SQL Server Execution Times:
       CPU time = 547 ms,  elapsed time = 669 ms.
    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 0 ms.
    

    いずれの場合も、オプティマイザはクエリを再配置するほどスマートです。

    EXISTS をよく使用します ただし(私の意見)。 EXISTS を使用する 1 つの使用例 2 番目のテーブル結果セットを返したくない場合です。

    Martin Smith からのクエリに従って更新:

    以下のクエリを実行して、2 番目のテーブルに参照が存在する最初のテーブルから行を取得する最も効果的な方法を見つけました。

    SELECT DISTINCT c.*
    FROM Customers c
    JOIN Orders o ON o.custid = c.custid   
    
    SELECT c.*
    FROM Customers c
    INNER JOIN (SELECT DISTINCT custid FROM Orders) AS o ON o.custid = c.custid
    
    SELECT *
    FROM Customers C
    WHERE EXISTS(SELECT 1 FROM Orders o WHERE o.custid = c.custid)
    
    SELECT *
    FROM Customers c
    WHERE custid IN (SELECT custid FROM Orders)
    

    上記のすべてのクエリは、2 番目の INNER JOIN を除いて同じコストを共有します 、残りは同じ計画です。

    メモリー付与:
    このクエリ

    SELECT DISTINCT c.*
    FROM Customers c
    JOIN Orders o ON o.custid = c.custid 
    

    の必要なメモリ付与

    このクエリ

    SELECT c.*
    FROM Customers c
    INNER JOIN (SELECT DISTINCT custid FROM Orders) AS o ON o.custid = c.custid 
    

    ..

    の必要なメモリ許可

    CPU 時間、読み取り:
    クエリの場合:

    SELECT DISTINCT c.*
    FROM Customers c
    JOIN Orders o ON o.custid = c.custid   
    
    (20000 row(s) affected)
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 48, logical reads 1344, physical reads 96, read-ahead reads 1248, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Orders'. Scan count 5, logical reads 3929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Customers'. Scan count 5, logical reads 322, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
     SQL Server Execution Times:
       CPU time = 1453 ms,  elapsed time = 781 ms.
    

    クエリの場合:

    SELECT c.*
    FROM Customers c
    INNER JOIN (SELECT DISTINCT custid FROM Orders) AS o ON o.custid = c.custid
    
    (20000 row(s) affected)
    Table 'Customers'. Scan count 5, logical reads 322, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Orders'. Scan count 5, logical reads 3929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
     SQL Server Execution Times:
       CPU time = 1499 ms,  elapsed time = 403 ms.
    


    1. mycliを使用して、ターミナルでMariaDB/MySQLを快適に学習してください。

    2. 何千もの WHERE 句を含む SQL クエリを最適化する方法

    3. Mysql-1つのクエリで複数のテーブルから削除

    4. SQL FLOAT:奇妙な数学エラーを回避するのに役立つ3つのポイント