web-dev-qa-db-ja.com

クロス適用のクエリからネストされたMicrosoft SQL Server 2014

OUTER APPLYステートメントでネストされたクエリから選択する場合、ネストされたクエリは特定の状況で1回だけ評価されるようです。

Azureフィードバックフォーラムに報告されたバグ: https://feedback.Azure.com/forums/908035-sql-server/suggestions/39428632-Microsoft-sql-server-2014-incorrect-result-when-s =

これは予期された動作ですか、それともドキュメントに何か不足していますか、それともSQL Serverのバグですか?

また、すべての行に対してネストされたクエリの評価を強制する可能性はありますか?

テストケース1

VALUESのすべての行のネストされたFROMクエリを評価します(予想外の動作)

SELECT
    v,
    v2
FROM
    (VALUES (1), (2), (3), (4)) AS inner_query(v)
    OUTER APPLY (
        SELECT
            MAX(inner_v2) AS v2
        FROM (
            SELECT 
                15 AS id,
                v AS inner_v2
        ) AS outer_query
        GROUP BY id
    ) AS outer_apply

結果:

| v | v2|
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |

テストケース2

また、VALUESのすべての行に対してネストされたFROMクエリを評価します(予想外の動作)

SELECT
    v,
    v2
FROM
    (VALUES (1), (2), (3), (4)) AS inner_query(v)
    OUTER APPLY (
        SELECT
            MAX(inner_v2) AS v2
        FROM (
            SELECT 
                15 AS id,
                v AS inner_v2
            UNION ALL
            SELECT
                id AS id,
                TestCaseTemp2.v AS inner_v2
            FROM
                (VALUES (1337, 0)) AS TestCaseTemp2(id, v)
            WHERE TestCaseTemp2.v != 0
        ) AS outer_query
        GROUP BY id
    ) AS outer_apply;

結果:

| v | v2|
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |

テストケース3

ネストされたFROMクエリを1回だけ評価します

CREATE TABLE TestCaseTemp
(
    id int,
    v int
);
INSERT INTO TestCaseTemp VALUES (1337, 0);

SELECT
    v,
    v2
FROM
    (VALUES (1), (2), (3), (4)) AS inner_query(v)
    OUTER APPLY (
        SELECT
            MAX(inner_v2) AS v2
        FROM (
            SELECT 
                15 AS id,
                v AS inner_v2
            UNION ALL
            SELECT
                id AS id,
                TestCaseTemp.v AS inner_v2
            FROM
                TestCaseTemp
            WHERE TestCaseTemp.v != 0
        ) AS outer_query
        GROUP BY id
    ) AS outer_apply;

DROP TABLE TestCaseTemp;

結果:

| v | v2|
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
8
Phist0ne

これはSQL Serverのバグですか?

はい、確かに、最終結果のすべての行に返される_1_は、外部入力の最初の行にのみ存在するため、後続の行のスコープにも含めないでください。 Paul White here が詳細に検討したのと同じ基本的な問題のように見えます。

私は最後のクエリをdbfiddle(SQL Server 2019)で実行し、ここに計画を貼り付けました https://www.brentozar.com/pastetheplan/?id=Sy4sBB5lI ソートが4回実行されるようです(1回だけ)外側の行ごとに)が、何らかの理由で再バインドではなく巻き戻しなので、その種類の子演算子を2回以上呼び出さないでください。これはバグであり、外部結合(_Union1004_)の相関パラメーターへの参照により、値が変更されたときに再バインドが発生します。その結果、プランのNode 5での_Union1004_への参照は再評価されません。

ここで報告したようです https://feedback.Azure.com/forums/908035-sql-server/suggestions/39428632-Microsoft-sql-server-2014-incorrect-result-when-s

すべての行に対してネストされたクエリの評価を強制する可能性はありますか?

クエリヒントの追加OPTION (MERGE UNION)はあなたの例で機能しますが、これがすべてのケースでバグを回避するのに必ずしも十分であるかどうかはわかりませんが、リンクされたPaul Whiteの回答からは機能するはずです。あなたの例の場合、それはソートで 下にプッシュダウン として機能するため、結合された結果全体ではなく、TestCaseTemp行のみを巻き戻します。適切なインデックスを追加して、並べ替えを完全に削除することもできます。

10
Martin Smith