web-dev-qa-db-ja.com

バッチモードのウィンドウ集計で算術オーバーフローが発生するのはなぜですか?

次のクエリは、ウィンドウストアされたSUM1500 total rowsの列ストアテーブルに対して実行します。それぞれの値は0または1であり、INTデータ型をオーバーフローします。なぜこうなった?

SELECT a, p, s, v, m, n,
    SUM(CASE WHEN n IS NULL THEN 0 ELSE 1 END)
        OVER (PARTITION BY s, v, a ORDER BY p) AS lastNonNullPartition
FROM (
    SELECT a, p, s, v, m, n,
        RANK() OVER (PARTITION BY v, s, a, p ORDER BY m) AS rank
    FROM #t /* A columnstore table with 1,500 rows */
)  x
WHERE x.rank = 1
--Msg 8115, Level 16, State 2, Line 1521
--Arithmetic overflow error converting expression to data type int.

完全なスクリプト

完全に含まれている再現スクリプトについては、このファイルを参照してください。

クエリプラン

これは、注釈付きの推定クエリプランです( プランの貼り付けの完全なXML )。

enter image description here

正常に実行される同様のクエリ

次のいずれかの変更が行われた場合、エラーは発生しません。

  • トレースフラグ8649を使用して、並列処理のコストしきい値に関係なく並列プランを優先します
  • トレースフラグ9453を使用してバッチモードを無効にする
  • COUNT関数の代わりにSUM集約関数を使用する
  • WHERE x.rank = 1述語を削除する

たとえば、次のクエリは正常に実行されます。

SELECT a, p, s, v, m, n,
    SUM(CASE WHEN n IS NULL THEN 0 ELSE 1 END)
        OVER (PARTITION BY s, v, a ORDER BY p) AS lastNonNullPartition
FROM (
    SELECT a, p, s, v, m, n,
        RANK() OVER (PARTITION BY v, s, a, p ORDER BY m) AS rank
    FROM #t /* A columnstore table with 1,500 rows */
)  x
WHERE x.rank = 1
OPTION (QUERYTRACEON 9453/* Disable batch mode */) 
11
Geoff Patterson

複数のコメント者がこの問題を再現できました。 SQL Server 2017 CU10で問題が解決したと当初は考えていましたが、CU10を含め、試行したすべてのバージョンのSQL Serverでエラーを再現できることがわかりました。ただし、一部のコメンターは、同じスクリプトが常にエラーをトリガーするとは限らない可能性のある要素を観察しました。

最大の合計が1,500である非負の数値のセット全体で合計を計算することが32ビット整数をオーバーフローする可能性がある論理的な方法がないため、これはバッチモードのウィンドウ集約演算子のバグであると考えられます。 SQL Server 2016の新しいオペレーターであるため、解決すべきEdgeのケースがまだある可能性があると想定するのは合理的です。

これはマイクロソフトに提出したバグレポートです

応答は:

これはSQL Server 2019 CTP 2.1で修正され、Azure SQL Databaseでもまもなく修正される予定です。

6
Geoff Patterson