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

SQLServerの条件付きフロー

    テストを次のように書き直します

    IF CASE
         WHEN EXISTS (SELECT ...) THEN CASE
                                       WHEN EXISTS (SELECT ...) THEN 1
                                     END
       END = 1  
    

    これにより、ここで説明するように短絡が保証されますが、オプティマイザーに任せるのではなく、事前に評価するために最も安価なものを選択する必要があることを意味します。

    以下の非常に限られたテストでは、テスト時に次のことが当てはまるようでした

    1。 EXISTS AND EXISTS

    EXISTS AND EXISTS バージョンが最も問題があるようです。これにより、いくつかの外側の半結合がチェーンされます。いずれの場合も、最初に安価なテストを実行するためにテストの順序を再調整しませんでした(このブログ投稿の後半で説明されている問題)。 IF ...で バージョンは短絡していなかったので、それがあったとしても何の違いもありませんでした。ただし、この結合された述語がWHEREに配置された場合 条項は計画が変更され、実行 再配置が有益であった可能性があるように短絡します。

    /*All tests are testing "If False And False"*/
    
    IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
    PRINT 'Y'
    /*
    Table 'spt_values'. Scan count 1, logical reads 9
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
    AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
    PRINT 'Y'
    /*
    Table 'spt_monitor'. Scan count 1, logical reads 1
    Table 'spt_values'. Scan count 1, logical reads 9
    */
    
    SELECT 1
    WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
    AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_values'. Scan count 1, logical reads 9
    
    */
    

    これらすべての計画は非常に似ているように見えます。 SELECT 1 WHERE ...の動作が異なる理由 バージョンとIF ... 前者の場合、条件がfalseの場合、正しい動作は結果を返さないため、OUTER SEMI JOINSをチェーンするだけです。 1つが偽の場合、ゼロ行は次の行に繰り越されます。

    ただし、IF バージョン常に 1またはゼロの結果を返す必要があります。このプランは、外部結合でプローブ列を使用し、EXISTSの場合、これをfalseに設定します テストに合格しません(単に行を破棄するのではありません)。これは、次の結合に常に1つの行がフィードされ、常に実行されることを意味します。

    CASE バージョンの計画は非常に似ていますが、PASSTHRUを使用しています 前のTHENの場合、JOINの実行をスキップするために使用する述語 条件が満たされていません。 ANDを組み合わせた理由がわかりません sは同じアプローチを使用しません。

    2。 EXISTS OR EXISTS

    EXISTS OR EXISTS バージョンは連結を使用しました(UNION ALL )外部半結合への内部入力としての演算子。この配置は、最初の行が返されるとすぐに内側からの行の要求を停止できることを意味します(つまり、効果的に短絡できます)。4つのクエリはすべて、より安価な述語が最初に評価された同じ計画になりました。

    /*All tests are testing "If True Or True"*/
    
    IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1)  
    OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
    OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1) 
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1)  
    OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
    OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1) 
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    

    3。 ELSEを追加する

    ANDを変換するためにドモルガンの法則を試してみることが私には思い浮かびました。 ORへ それが何か違いを生んだかどうかを確認してください。最初のクエリを変換すると

    IF NOT ((NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)))
    PRINT 'Y'
    ELSE
    PRINT 'N'
    /*
    Table 'spt_monitor'. Scan count 1, logical reads 1
    Table 'spt_values'. Scan count 1, logical reads 9
    */
    

    したがって、これでも短絡動作に違いはありません。ただし、NOTを削除した場合 IF ... ELSEの順序を逆にします 現在行う条件 短絡!

    IF (NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1))
    PRINT 'N'
    ELSE
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    


    1. EasysoftOracle®ドライバーのSOA環境への導入

    2. MySQLルートパスワードをリセットする方法

    3. 圧縮とそのパフォーマンスへの影響

    4. mysql_num_rows():指定された引数は有効なMySQL結果リソースではありません