Meine wilde Vermutung: "effizienter" bedeutet "weniger Zeit wird benötigt, um die Prüfung durchzuführen" (Zeitvorteil). Dies kann auch bedeuten, dass "weniger Speicher erforderlich ist, um die Prüfung durchzuführen" (Platzvorteil). Es könnte auch bedeuten, dass "weniger Nebenwirkungen" vorliegen (z. B., dass etwas nicht gesperrt oder für kürzere Zeit gesperrt wird) ... aber ich habe keine Möglichkeit, diesen "zusätzlichen Vorteil" zu kennen oder zu überprüfen.
Ich kann mir keinen einfachen Weg vorstellen, um nach einem möglichen Platzvorteil zu suchen (was, denke ich, nicht so wichtig ist, wenn Speicher heutzutage billig ist). Auf der anderen Seite ist es nicht so schwierig, den möglichen Zeitvorteil zu überprüfen: Erstellen Sie nur zwei Tabellen, die mit Ausnahme der Einschränkung identisch sind. Fügen Sie eine ausreichend große Anzahl von Zeilen ein, wiederholen Sie diese einige Male und überprüfen Sie die Timings.
Dies ist die Tabelleneinstellung:
CREATE TABLE t1
(
id serial PRIMARY KEY,
value integer NOT NULL
) ;
CREATE TABLE t2
(
id serial PRIMARY KEY,
value integer
) ;
ALTER TABLE t2
ADD CONSTRAINT explicit_check_not_null
CHECK (value IS NOT NULL);
Dies ist eine zusätzliche Tabelle zum Speichern von Timings:
CREATE TABLE timings
(
test_number integer,
table_tested integer /* 1 or 2 */,
start_time timestamp without time zone,
end_time timestamp without time zone,
PRIMARY KEY(test_number, table_tested)
) ;
Und dies ist der Test, der mit pgAdmin III und der pgScript-Funktion durchgeführt wurde .
declare @trial_number;
set @trial_number = 0;
BEGIN TRANSACTION;
while @trial_number <= 100
begin
-- TEST FOR TABLE t1
-- Insert start time
INSERT INTO timings(test_number, table_tested, start_time)
VALUES (@trial_number, 1, clock_timestamp());
-- Do the trial
INSERT INTO t1(value)
SELECT 1.0
FROM generate_series(1, 200000) ;
-- Insert end time
UPDATE timings
SET end_time=clock_timestamp()
WHERE test_number=@trial_number and table_tested = 1;
-- TEST FOR TABLE t2
-- Insert start time
INSERT INTO timings(test_number, table_tested, start_time)
VALUES (@trial_number, 2, clock_timestamp());
-- Do the trial
INSERT INTO t2(value)
SELECT 1.0
FROM generate_series(1, 200000) ;
-- Insert end time
UPDATE timings
SET end_time=clock_timestamp()
WHERE test_number=@trial_number and table_tested = 2;
-- Increase loop counter
set @trial_number = @trial_number + 1;
end
COMMIT TRANSACTION;
Das Ergebnis ist in der folgenden Abfrage zusammengefasst:
SELECT
table_tested,
sum(delta_time),
avg(delta_time),
min(delta_time),
max(delta_time),
stddev_pop(delta_time)
FROM
(
SELECT
table_tested, extract(epoch from (end_time - start_time)) AS delta_time
FROM
timings
) AS delta_times
GROUP BY
table_tested
ORDER BY
table_tested ;
Mit folgenden Ergebnissen:
table_tested | sum | min | max | avg | stddev_pop
-------------+---------+-------+-------+-------+-----------
1 | 176.740 | 1.592 | 2.280 | 1.767 | 0.08913
2 | 177.548 | 1.593 | 2.289 | 1.775 | 0.09159
Ein Diagramm der Werte zeigt eine wichtige Variabilität:
In der Praxis ist CHECK (Spalte IST NICHT NULL) also etwas langsamer (um 0,5%). Dieser kleine Unterschied kann jedoch auf einen beliebigen Grund zurückzuführen sein, vorausgesetzt, die Variabilität der Zeitabläufe ist weitaus größer. Es ist also statistisch nicht signifikant.
Aus praktischer Sicht würde ich das "effizientere" System sehr ignorieren NOT NULL
, da ich nicht wirklich sehe, dass es von Bedeutung ist. Ich halte das Fehlen AccessExclusiveLock
eines von Vorteil.