Dự đoán hoang dã của tôi: "hiệu quả hơn" có nghĩa là "cần ít thời gian hơn để thực hiện kiểm tra" (lợi thế về thời gian). Điều này cũng có nghĩa là "cần ít bộ nhớ hơn để thực hiện kiểm tra" (lợi thế về không gian). Điều này cũng có nghĩa là "có ít tác dụng phụ hơn" (chẳng hạn như không khóa hoặc khóa trong thời gian ngắn hơn) ... nhưng tôi không có cách nào để biết hoặc kiểm tra "lợi thế bổ sung" đó.
Tôi không thể nghĩ ra một cách dễ dàng để kiểm tra lợi thế không gian có thể có (mà tôi đoán là không quan trọng khi bộ nhớ ngày nay rẻ). Mặt khác, không khó để kiểm tra lợi thế về thời gian có thể: chỉ cần tạo hai bảng giống nhau, ngoại trừ ràng buộc duy nhất. Chèn một số lượng hàng đủ lớn, lặp lại một vài lần và kiểm tra thời gian.
Đây là thiết lập bảng:
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);
Đây là một bảng phụ, được sử dụng để lưu trữ thời gian:
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)
) ;
Và đây là thử nghiệm được thực hiện, sử dụng pgAdmin III và tính năng 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;
Kết quả được tóm tắt trong truy vấn sau:
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 ;
Với kết quả như sau:
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
Một biểu đồ của các giá trị cho thấy một sự thay đổi quan trọng:
Vì vậy, trong thực tế, KIỂM TRA (cột IS KHÔNG NULL) chậm hơn một chút (bằng 0,5%). Tuy nhiên, sự khác biệt nhỏ này có thể là do bất kỳ lý do ngẫu nhiên nào, với điều kiện là độ biến thiên của thời gian lớn hơn nhiều. Vì vậy, nó không có ý nghĩa thống kê.
Từ quan điểm thực tế, tôi sẽ rất bỏ qua "hiệu quả hơn" NOT NULL
, bởi vì tôi không thực sự thấy nó có ý nghĩa; trong khi tôi nghĩ rằng sự vắng mặt của một AccessExclusiveLock
là một lợi thế.