Ma conjecture sauvage: "plus efficace" signifie "moins de temps est nécessaire pour effectuer la vérification" (avantage de temps). Cela peut également signifier «moins de mémoire est nécessaire pour effectuer la vérification» (avantage d'espace). Cela pourrait également signifier "a moins d'effets secondaires" (comme ne pas verrouiller quelque chose ou le verrouiller pour des périodes de temps plus courtes) ... mais je n'ai aucun moyen de connaître ou de vérifier cet "avantage supplémentaire".
Je ne peux pas penser à un moyen facile de vérifier un éventuel avantage d'espace (ce qui, je suppose, n'est pas si important lorsque la mémoire est bon marché de nos jours). D'un autre côté, ce n'est pas si difficile de vérifier le gain de temps possible: il suffit de créer deux tables qui sont les mêmes, à la seule exception de la contrainte. Insérez un nombre suffisamment important de lignes, répétez plusieurs fois et vérifiez les horaires.
Voici la configuration de la table:
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);
Il s'agit d'un tableau supplémentaire, utilisé pour stocker les horaires:
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)
) ;
Et c'est le test effectué, en utilisant pgAdmin III et la fonctionnalité pgScript .
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;
Le résultat est résumé dans la requête suivante:
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 ;
Avec les résultats suivants:
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
Un graphique des valeurs montre une variabilité importante:
Ainsi, en pratique, le CHECK (colonne IS NOT NULL) est très légèrement plus lent (de 0,5%). Cependant, cette petite différence peut être due à une raison aléatoire, à condition que la variabilité des timings soit bien plus importante que cela. Ce n'est donc pas statistiquement significatif.
D'un point de vue pratique, j'ignorerais beaucoup le "plus efficace" NOT NULL
, car je ne vois pas vraiment qu'il est significatif; alors que je pense que l'absence d'un AccessExclusiveLock
est un avantage.