Was sind die Konsequenzen, wenn in PostgreSQL NICHT NULL für Felder angegeben wird, die nicht null sein dürfen?


10

Ich habe eine Anwendung (Daten werden in PostgreSQL gespeichert), in der die meisten Felder in den Tabellen immer nicht null sind, aber das Schema für diese Tabellen erzwingt dies nicht. Schauen Sie sich zum Beispiel diese gefälschte Tabelle an:

CREATE TABLE "tbl" (
    "id" serial,
    "name" varchar(40),
    "num" int,
    "time" timestamp
    PRIMARY KEY ("id"),
    UNIQUE ("id")
);

Auch name, num, timenicht explizit angegeben ist, wie NOT NULL, in Wirklichkeit sind sie, weil die Durchsetzung auf der Anwendungsseite passiert.


Meiner Meinung nach sollte es geändert werden, aber der Kontrapunkt ist, dass die Anwendungsebene sicherstellt, dass hier keine Nullwerte angezeigt werden können und niemand anderes die Tabelle manuell ändert.

Meine Frage lautet : Was sind die Vorteile (Leistung, Speicher, Konsistenz, etwas anderes) und die Nachteile (vorausgesetzt, ich habe bereits überprüft, dass im Moment keine Nullen vorhanden sind, und aus der Geschäftslogik sollten keine Nullen vorhanden sein), indem Sie eine setzen explizite NOT NULLEinschränkung?

Wir haben einen guten Codeüberprüfungsprozess und eine einigermaßen gute Dokumentation, sodass die Möglichkeit, dass eine neue Person etwas festlegt, das diese Einschränkung verletzt, nicht ausreicht, um die Änderung zu rechtfertigen.

Dies ist nicht meine Entscheidung, deshalb suche ich genau nach anderen Rechtfertigungen. Meiner Meinung nach, wenn etwas nicht null sein kann und Sie in einer Datenbank angeben können, dass etwas nicht null ist, dann tun Sie es einfach. Besonders wenn die Änderung super einfach ist.


1
In dieser Antwort finden Sie Überlegungen zu Nullen und Speicherplatz: stackoverflow.com/questions/5008753/… Kurz gesagt, wenn Ihre Tabelle mehr als 8 Spalten und mindestens 1 nullfähige Spalte enthält, benötigt die Tabelle mehr Bytes pro Zeile als alle Spalten definiert nicht null.
Ypercubeᵀᴹ

1
@ ypercubeᵀᴹ: Um genau zu sein, wird die Null-Bitmap nur pro Zeile hinzugefügt, wenn die Zeile einen tatsächlichen Nullwert enthält: stackoverflow.com/a/7654497/939860 . Daher NOT NULLEinschränkungen haben keine direkte Auswirkung auf Speichergröße. Da alle Spalten definiert sind NOT NULL, kann es natürlich zunächst keine Null-Bitmap geben. Auf der anderen Seite: Die Speichergröße ist normalerweise viel kleiner, wenn Sie NULL anstelle von "leeren" oder Dummy-Werten für Spalten ohne tatsächlichen Wert verwenden, da die Null-Bitmap vergleichsweise viel kleiner ist (mit Ausnahme seltener Kantenfälle).
Erwin Brandstetter

@ErwinBrandstetter mein schlechtes dann hatte diesen Teil nicht verstanden. Für Spalten ohne Nullwerte gibt es also keinen wirklichen Unterschied im Speicher, unabhängig davon, ob Sie sie als NULL oder NICHT NULL definieren. Richtig? Ist das auch für den Indexspeicherplatz so?
Ypercubeᵀᴹ

5
"Die Anwendungsebene stellt sicher, dass hier keine Nullwerte angezeigt werden können." Nein, das ist nicht der Fall. Es könnte sicherstellen , dass eine Anwendung nicht Einsatz nulls. Aber ich habe psql (zum Beispiel) und kann absichtlich und versehentlich Nullen einfügen, ohne dass Ihre Anwendung davon erfährt.
Mike Sherrill 'Cat Recall'

4
Die einzige Anwendung, die sicherstellen kann, dass niemand die Tabelle manuell ändert, ist die Datenbank selbst.
Mike Sherrill 'Cat Recall'

Antworten:


9

Was passiert, wenn ein neuer Programmierer eintrifft und eine App für diese Datenbank schreiben muss? Sie wissen nicht , dass Feld x hat zu sein NOT NULL.

Ein anderes Programm könnte annehmen, dass alle Feld-Xs NOT NULLzum Durchführen von Zählungen bestimmt sind, aber einige sind jetzt NULLauf das neue Programm zurückzuführen, was zu inkonsistenten und schwer zu verfolgenden Fehlern führt.

IMHO ist es immer am besten, Datenintegritätsregeln so nah wie möglich an den Daten, dh in der Datenbank, durchzusetzen. Auf diese Weise können neue Apps und / oder Programmierer Ihre Daten nicht durcheinander bringen.

Programmierer, Anwendungen, Sprachen und Frameworks kommen und gehen. Daten und Datenbanken bleiben in der Regel bestehen. Die Datenbank ist Ihre letzte Verteidigungslinie gegen inkonsistente, möglicherweise fehlerhafte Daten.

Machen maximale Nutzung Ihrer Datenbank Integrität Randbedingungserzwingung Mechanismen, auch auf Kosten der Leistung. Ein langsames System, das korrekte Ergebnisse liefert, ist einem schnellen System, das etwas falsch macht, unendlich überlegen!


1
IMHO it is always best to enforce data integrity rules as near to the data as possibleDas ist eigentlich das gleiche wie das Bauchgefühl, über das ich geschrieben habe. Und genau deshalb suche ich nach echten Rechtfertigungen. Wir haben eine Codeüberprüfung und eine gute Dokumentation, sodass Bedenken, dass ein neuer Entwickler etwas nicht weiß, nicht ausreichen, um die Änderung zu rechtfertigen.
Salvador Dali

4
Codeüberprüfungen und eine gute Dokumentation garantieren Sie nicht gegen (Programmier- oder andere) Fehler.
Ypercubeᵀᴹ

2
Und wie viele REAL PROGRAMMERSlesen die gesamte (oder sogar eine) Dokumentation, bevor sie in ein Projekt geraten, in dem sie sich in einer engen Frist befinden?
Vérace

3
Ich habe einmal eine Überprüfung in einer Bank durchgeführt, die die gleiche Einstellung für ihr Data Warehouse hatte. In ihrem Fall - keine referenzielle Integrität. Nun, es kommt vor, dass 40% der älteren Daten Müll waren, weil jemand die Dokumentation nicht gelesen und Daten in Nachschlagetabellen gelöscht hatte. Sie vertrauen Codeüberprüfungen und Dokumentationen nicht mit Datenintegrität - Sie machen dies in der Datenbank explizit.
TomTom

5

Wie bereits von anderen in Kommentaren zitiert, kann das Hinzufügen NOT NULLzu Ihrer Tabellenspezifikation die Leistung Ihrer Abfragen erheblich verbessern (zusätzlich zu den sehr guten methodischen Gründen, die in einer anderen Antwort angegeben sind).

Der Grund dafür ist, dass der Abfrageoptimierer, der weiß, dass eine Spalte keinen NULLWert haben kann, spezielle Tests für solche Werte ausschließen kann, wie im Fall NOT INvs. NOT EXISTSSie können zum Beispiel dieses Blog sehen , in dem gezeigt wird, dass das Nichtdeklarieren eines Felds NOT NULL(wenn die Tabelle immer Nicht-Null-Werte enthält) mit einer bestimmten Abfrage die Ausführungszeit von 500% erhöht. Das Ergebnis wird für SQL Server angezeigt, aber ein ähnliches Verhalten kann in anderen relationalen DBMS wie Ihrem vorhanden sein (ganz zu schweigen von der Tatsache, dass Ihre Datenbank auf andere Systeme portiert werden könnte). Eine allgemeine Regel, die Sie annehmen können, lautet, dass effizientere Zugriffspläne erstellt werden können, wenn dem Abfrageoptimierer mehr Informationen zur Verfügung stehen.


Vielen Dank. Dies ist die Art von Antwort, nach der ich gesucht habe.
Salvador Dali

5
Spalten, die niemals NULL enthalten, sollten NOT NULLaus mehreren Gründen definiert werden, kein Argument dafür. Der Link zum Blog über SQL Server gilt jedoch nicht für Postgres und beweist keine der von Ihnen erwähnten Auswirkungen auf die Leistung. Ich sage nicht, dass es keine gibt, aber ich würde gerne tatsächliche Beweise sehen .
Erwin Brandstetter

@ErwinBrandstetter, ich hatte sehr hohe Erwartungen an den PostgreSQL-Optimierer :( Nach mehreren Tests fand ich keine signifikanten Unterschiede in der NOT IN-Abfrage, die im Blog in PostgreSQL mit und ohne NOT NULL-Einschränkung dargestellt wurde. Daher habe ich die Antwort geändert und frage Sie, ob Sie denken, dass ich es insgesamt löschen sollte.
Renzo

Nein, ich denke nicht, dass es gelöscht werden sollte. Es hat 5 + Stimmen und zum einen keine Abwertung.
Ypercubeᵀᴹ

Die Semantik von not infür nullfähige Spalten ist jedoch unterschiedlich, sodass es einen Unterschied im Plan zwischen den beiden geben muss.
Martin Smith

2

Auswirkungen auf den Weltraum

Über die Auswirkungen auf den Weltraum wird in diesem Beitrag von @Erwin Brandstetter gesprochen

Kurz gesagt, Sie speichern ein totalColumns - 8Bit, das auf das nächste Byte (oder MAXALIGN) aufgerundet ist , wenn Ihre Datenbank dies hat

  1. Mehr als 8 Spalten
  2. ALLE Spalten in der Tabelle sindNOT NULL

Auswirkungen auf die Leistung

In diesem Beitrag über SE von @Erwin Brandstetter sagt er jedoch

  1. "Das Setzen von NOT NULL hat per se keine Auswirkung auf die Leistung. Einige Zyklen für die Prüfung - irrelevant."
  2. "... indem Sie tatsächlich NULL-Werte anstelle von Dummy-Werten verwenden. Abhängig von den Datentypen können Sie viel Speicherplatz und RAM sparen und so alles beschleunigen."

@Renzo hat eine Antwort , die über die Auswirkungen auf die Leistung spricht - ich würde annehmen, dass nichts davon auf PostgreSQL anwendbar ist . Ich kann nichts , dass erhärtet finden alle davon als relevant zu PostgreSQL. Welche Zyklen auch immer gespeichert werden, kann selbst in der rudimentärsten Abfrage nicht quantifiziert werden.

CREATE TABLE foo (
  a int,
  b int NOT NULL,
  x float,
  y float NOT NULL
);

INSERT INTO foo ( a, b, x, y )
SELECT x, x, x, x
FROM generate_series(1,1E7) AS X(x);

EXPLAIN ANALYZE SELECT 1/a FROM foo;
EXPLAIN ANALYZE SELECT 1/b FROM foo;
EXPLAIN ANALYZE SELECT 1/x FROM foo;
EXPLAIN ANALYZE SELECT 1/y FROM foo;

Außerdem habe ich einige Tests durchgeführt, um festzustellen, ob NULL-Indizes immer schneller waren, und das konnte ich nicht belegen. Sie finden diesen äußerst nützlichen Thread von Scott Marlowe in den Mailinglisten, in dem es darum geht, dass der Abfrageplaner in 9.1 einen Teilindex für unterschiedliche WHERE-Klauseln verwenden kann. Ich habe dies getestet, indem ich Folgendes ausgeführt habe

CREATE TABLE foo ( a int );
CREATE TABLE bar ( a int NOT NULL );
INSERT INTO foo
  SELECT null FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT null FROM generate_series(1,1e5) AS x
;
INSERT INTO bar
  SELECT 0 FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT 0 FROM generate_series(1,1e5) AS x
;

Jetzt habe ich die Indizes erstellt,

CREATE INDEX foobar ON foo(a) WHERE a IS NOT NULL;
CREATE INDEX barbar ON bar(a) WHERE a <> 0;

In beiden Fällen konnte der Planer den Index bei der Auswahl verwenden = 10und bei der Suche nach NULL bzw. 0 einen seq-Scan verwenden. Beide Teilindizes waren gleich groß. Die vollständigen Indizes (nicht gezeigt) hatten dieselbe Größe. Nach der gleichen Methode habe ich die Tabelle mit einer Folge von 1..1e5und dem einen Null / 0-Wert und einer anderen Folge von geladen 1..1e5. Beide Methoden konnten die Null / 0 mit einem Index finden, der die gesamte Tabelle abdeckt.

TLDR; Zusammenfassung

Ich kann auf die eine oder andere Weise nichts über die meisten Leistungsprobleme begründen, von denen ich dachte, dass sie es wert sind, getestet zu werden, um Unzulänglichkeiten des Planers einzubeziehen. Der Vorteil der Verwendung von null zum Speichern von RAM ist real. Der Speicherplatz, der durch die Nichtverwendung von null eingespart wird, ist vernachlässigbar. Dies ist eine Übertreibung bei Tabellen mit einer NULLABLESpalte oder weniger als 8 Spalten. In diesen Fällen wird kein Speicherplatz gespeichert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.