SQL Serverがインデックス付きビューの列がNULL可能ではないことを認識できるようにするにはどうすればよいですか?


9

SQL Server 2008で次のインデックス付きビューが定義されています(テスト目的でgistから作業スキーマダウンロードできます)。

CREATE VIEW dbo.balances
WITH SCHEMABINDING
AS
SELECT
      user_id
    , currency_id

    , SUM(transaction_amount)   AS balance_amount
    , COUNT_BIG(*)              AS transaction_count
FROM dbo.transactions
GROUP BY
      user_id
    , currency_id
;
GO

CREATE UNIQUE CLUSTERED INDEX UQ_balances_user_id_currency_id
ON dbo.balances (
      user_id
    , currency_id
);
GO

user_idcurrency_id、およびtransaction_amountすべてのように定義されているNOT NULLの列dbo.transactions。ただし、Management Studioのオブジェクトエクスプローラーでビュー定義を見ると、ビューの両方の列balance_amountと-able列transaction_countとしてマークさNULLれています。

私はいくつかのディスカッションを調べましたが、これはそれらの中で最も関連性が高く、SQL Serverがビュー列が常にであることをSQL Serverが認識するのに役立つ可能性のある関数のシャッフルを示唆していますNOT NULL。ただし、インデックス付きビューでは集約関数の式(たとえば、ISNULL()over SUM())は許可されていないため、私の場合、そのようなシャッフルは不可能です。

  1. SQL Serverはそれを認識し、私は助けることができる任意の方法があるbalance_amounttransaction_countしているNOT NULL-ableは?

  2. そうでない場合、これらの列が誤ってNULL-able と識別されることについて心配する必要がありますか?

    私が考えることができる2つの懸念は次のとおりです。

    • 残高ビューにマップされたアプリケーションオブジェクトは、残高の定義が正しくありません。
    • 非常に限られたケースでは、これらの2つの列がであるというビューからの保証がないため、クエリオプティマイザーは特定の最適化を利用できませんNOT NULL

    これらの懸念のいずれかは大きな問題ですか?他に覚えておくべき懸念はありますか?


はい、懸念があります。たとえば、ORMはnull許容型を作成するため、それらを使用する場合はコードで特別な注意が必要になります。
マルセル

最後にIsNull(...、0)で解決できる場合でも、これはnull可能ではないフィールド(集計なし)で再帰するときの再帰cteの問題のようです。
crokusek 2014年

回答:


10

user_idcurrency_id、およびtransaction_amountすべてのように定義されているNOT NULLの列dbo.transactions

SQL Serverには、null操作対象のフィールドがである場合でも、集合体がを生成できるという包括的な仮定があるようnot nullです。これは明らかに特定の場合に当てはまります。

create table foo(bar integer not null);
select sum(bar) from foo
-- returns 1 row with `null` field

group byような一般化バージョンにも当てはまりますcube

このより単純なテストケースは、集計がnull許容として解釈される点を示しています。

CREATE VIEW dbo.balances
with schemabinding
AS
SELECT
      user_id
    , sum(1)   AS balance_amount
FROM dbo.transactions
GROUP BY
      user_id
;
GO

IMOこれはSQL Serverの制限です(マイナーなものではあります)。他の一部のRDBMSでは、強制されず、オプティマイザへの手がかりを与えるためにのみ存在するビューに特定の制約を作成できますが、「一意性」はより可能性が高いと思います「nullability」よりも優れたクエリプランの生成に役立ちます


おそらくORMで使用するために列のnull可能性が重要な場合は、インデックス付きビューを、null可能でないことを単に保証する別のビューでラップすることを検討してISNULLください。

CREATE VIEW dbo.balancesORM
WITH SCHEMABINDING
AS
SELECT 
    B.[user_id],
    B.currency_id,
    balance_amount = ISNULL(B.balance_amount, 0),
    transaction_count = ISNULL(B.transaction_count, 0)
FROM dbo.balances AS B;

SSMSオブジェクトエクスプローラーの詳細


5

SQL Serverがこれらの列をnull可能ではないと明確に認識できないようにする方法はないと思います。たとえば、の式の定義方法ISNULLCOALESCE周りの順序を変更しようとすることはできますが、役に立ちません。 SUM()

また、見逃してしまう最適化があるとは思いません。これらの列には現在インデックスが作成されていないため、オプティマイザが別のアクセス方法を選択して、たとえばすべてのbalance_amount値が10000を超えるとは限らないのです。これらの列の1つに非クラスター化インデックスを作成すると、インデックスが存在しない場合よりもわずかに良い見積もりが得られるかもしれませんが、これはnullの可能性とは関係ありません。

パフォーマンスの観点から、これについてはあまり心配しません。私は戻って、長年にわたって作成した一連のインデックス付きビューを見ました。これらの集計列はすべてnull可能です。彼らはうまく機能します。

オブジェクトマッピングに関しては、ここでも心配する必要はありません。アプリケーションはインデックス付きビューを更新できないため、それがbalance_amount可能かどうかは関係ありませんnull。を受け取ることは決してなくnull、を書こうとすることもできないnullので<shrug>



@Aaron、オブジェクトマッピングについて:マッパーはおそらく実際には使用されないnull許容型を持つ役に立たない/誤解を招くオブジェクトを生成する可能性があるため、一見の価値があると思います。
マルセル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.