Wie kann ich SQL Server dabei helfen, zu erkennen, dass meine indizierte Ansichtsspalte NICHT NULL-fähig ist?

9

Ich habe die folgende indizierte Ansicht in SQL Server 2008 definiert (Sie können ein Arbeitsschema zu Testzwecken von gist herunterladen ):

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_id,, currency_idund transaction_amountsind alle als NOT NULLSpalten in definiert dbo.transactions. Aber wenn ich mir die Sichtdefinition in Management Studio Object Explorer, es Markierungen sowohl balance_amountund transaction_countals NULL-able Spalten in der Ansicht.

Ich habe mir mehrere Diskussionen angesehen, von denen diese die relevanteste ist. Diese weisen darauf hin, dass durch das Mischen von Funktionen SQL Server möglicherweise erkennt, dass eine Ansichtsspalte immer vorhanden ist NOT NULL. In meinem Fall ist ein solches Mischen jedoch nicht möglich, da Ausdrücke für Aggregatfunktionen (z. B. ein ISNULL()Over-Over SUM()) in indizierten Ansichten nicht zulässig sind .

  1. Gibt es eine Möglichkeit, SQL Server erkennen , dass helfen kann , balance_amountund transaction_countsind NOT NULL-able?

  2. Wenn nicht, sollte ich Bedenken haben, dass diese Spalten fälschlicherweise als NULL-able identifiziert werden ?

    Die zwei Bedenken, an die ich denken könnte, sind:

    • Alle Anwendungsobjekte, die der Saldenansicht zugeordnet sind, erhalten eine falsche Definition einer Bilanz.
    • In sehr begrenzten Fällen stehen dem Abfrageoptimierer bestimmte Optimierungen nicht zur Verfügung, da aus der Sicht dieser beiden Spalten keine Garantie besteht NOT NULL.

    Ist eines dieser Probleme eine große Sache? Gibt es noch andere Bedenken, die ich berücksichtigen sollte?

Nick Chammas
quelle
Ja, es gibt Bedenken, zum Beispiel, dass Ihr ORM nullfähige Typen erstellt, die wiederum besondere Sorgfalt im Code erfordern, wenn Sie sie verwenden, was in Ihrem Fall nutzlos (oder sogar irreführend) ist.
Marcel
Dies scheint auch ein Problem in einem rekursiven cte zu sein, wenn in einem nicht nullbaren Feld (kein Aggregat) rekursiv gearbeitet wird, obwohl ein IsNull (..., 0) am Ende heilen kann.
Crokusek

Antworten:

10

user_id,, currency_idund transaction_amountsind alle als NOT NULLSpalten in definiertdbo.transactions

Es scheint mir, dass SQL Server pauschal davon ausgeht, dass ein Aggregat ein gerades Ergebnis erzielen kann, nullwenn es sich um die Felder handelt, mit denen es arbeitet not null. Dies gilt offensichtlich in bestimmten Fällen:

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

Und gilt auch für die verallgemeinerten Versionen von group bylikecube

Dieser einfachere Testfall veranschaulicht den Punkt, an dem jedes Aggregat als nullbar interpretiert wird:

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

IMO ist dies eine (wenn auch geringfügige) Einschränkung von SQL Server. Einige andere RDBMS ermöglichen die Erstellung bestimmter Einschränkungen für Ansichten, die nicht erzwungen werden und nur existieren, um dem Optimierer Hinweise zu geben, obwohl ich der Meinung bin, dass "Eindeutigkeit" wahrscheinlicher ist Hilfe bei der Erstellung eines guten Abfrageplans als "Nullability"


Wenn die Nullbarkeit der Spalte wichtig ist, möglicherweise für die Verwendung mit einem ORM, sollten Sie die indizierte Ansicht in eine andere Ansicht einschließen, die einfach die Nicht-Nullfähigkeit garantiert, indem Sie 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;

Details zum SSMS-Objekt-Explorer

Jack sagt, versuchen Sie es mit topanswers.xyz
quelle
5

Ich glaube nicht, dass Sie SQL Server auf irgendeine Weise zwingen können, diese Spalten als nicht nullbar zu erkennen, obwohl dies eindeutig nicht der Fall ist. Sie können versuchen , die Reihenfolge zu ändern , wie definieren Sie ISNULL/ COALESCEum den Ausdruck im Innern SUM() , zum Beispiel, aber es wird nicht zu Hilfe.

Ich glaube auch nicht, dass es Optimierungen gibt, die Sie verpassen werden - diese Spalten sind derzeit nicht indiziert, daher kann der Optimierer keine andere Zugriffsmethode auswählen, um beispielsweise alle balance_amountWerte> 10000 zu bestimmen Wenn Sie einen nicht gruppierten Index für eine dieser Spalten erstellen, erhalten Sie möglicherweise etwas bessere Schätzungen als wenn der Index nicht vorhanden ist. Dies hat jedoch nichts mit der Nullfähigkeit zu tun.

Aus Performance-Sicht wäre ich darüber nicht allzu besorgt. Ich ging zurück und sah mir eine Reihe von indizierten Ansichten an, die ich im Laufe der Jahre erstellt habe. Diese Aggregationsspalten sind alle nullwertfähig. Sie funktionieren gut.

Auch bei der Objektzuordnung würde ich mir darüber keine Sorgen machen. Da die Anwendung die indizierte Ansicht nicht aktualisieren kann, spielt es keine Rolle, ob dies balance_amountmöglich ist null. Es wird niemals eine erhalten null, und es kann nicht versuchen, eine zu schreiben null, also <shrug>.

Aaron Bertrand
quelle
1
Pedantische Anmerkung: [Koaleszenz erlaubt nullbare Spalten, isnull nicht ].
Billinkc
@ Aaron, über Objektzuordnung: Ich halte es für einen Blick wert, da ein Mapper wahrscheinlich nutzlose / irreführende Objekte mit nullbaren Typen generiert, die niemals wirklich als solche verwendet werden.
Marcel