Моя дикая догадка: «более эффективный» означает «требуется меньше времени для выполнения проверки» (преимущество во времени). Это также может означать, что для выполнения проверки требуется меньше памяти (преимущество пространства). Это также может означать «имеет меньше побочных эффектов» (например, не блокировать что-либо или блокировать его на более короткие промежутки времени) ... но у меня нет способа узнать или проверить это «дополнительное преимущество».
Я не могу придумать простой способ проверить возможное космическое преимущество (которое, я думаю, не так важно, когда память сегодня дешева). С другой стороны, это не так сложно проверить на возможное преимущество во времени: просто создайте две одинаковые таблицы, с единственным исключением из ограничения. Вставьте достаточно большое количество строк, повторите несколько раз и проверьте время.
Это настройка таблицы:
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);
Это дополнительная таблица, используемая для хранения таймингов:
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)
) ;
И это тест, выполненный с использованием pgAdmin III и функции 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;
Результат суммируется в следующем запросе:
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 ;
Со следующими результатами:
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
График значений показывает важную изменчивость:
Таким образом, на практике CHECK (столбец IS NOT NULL) очень немного медленнее (на 0,5%). Однако это небольшое различие может быть вызвано любой случайной причиной, при условии, что изменчивость временных параметров намного больше, чем эта. Таким образом, это не является статистически значимым.
С практической точки зрения я бы очень проигнорировал «более эффективную» NOT NULL
, потому что я не вижу в ней значимости; в то время как я думаю, что отсутствие AccessExclusiveLock
является преимуществом.