Thành thật mà nói, lựa chọn tốt nhất là "không phải EAV". Xem xét việc sử dụng hstore
các trường, XML
hoặc json
.
Trong PostgreSQL, không có lợi thế về hiệu suất khi sử dụng bảng per-datatype. NULL
các giá trị được lưu trữ trong NULL
nhỏ gọn bitmap, vì vậy nó tạo ra rất ít khác biệt cho dù bạn có một bộ giá trị như (NULL, NULL, NULL, 42, NULL, NULL)
hoặc chỉ (42)
.
Điều này cũng cho phép bạn thêm CHECK
ràng buộc thực thi rằng chính xác một trường phải không phải là NULL
, vì vậy bạn không nhận được nhiều giá trị thuộc các loại khác nhau.
Demo:
regress=> CREATE TABLE eav_ugh (
entity_id integer,
int_value integer,
numeric_value numeric,
text_value text,
timestamp_value timestamp with time zone,
CONSTRAINT only_one_non_null CHECK (
(int_value IS NOT NULL AND numeric_value IS NULL AND text_value IS NULL AND timestamp_value IS NULL) OR
(int_value IS NULL AND numeric_value IS NOT NULL AND text_value IS NULL AND timestamp_value IS NULL) OR
(int_value IS NULL AND numeric_value IS NULL AND text_value IS NOT NULL AND timestamp_value IS NULL) OR
(int_value IS NULL AND numeric_value IS NULL AND text_value IS NULL AND timestamp_value IS NOT NULL)
)
);
CREATE TABLE
regress=> insert into eav_ugh (entity_id, numeric_value) select x, x from generate_series(1,5000) x;
INSERT 0 5000
regress=> select pg_relation_size('eav_ugh');
pg_relation_size
------------------
229376
(1 row)
regress=> CREATE TABLE no_null_cols(entity_id integer, numeric_value numeric);
CREATE TABLE
regress=> insert into no_null_cols (entity_id, numeric_value) select x, x from generate_series(1,5000) x;
INSERT 0 5000
regress=> select pg_relation_size('no_null_cols');
pg_relation_size
------------------
229376
(1 row)
regress=> SELECT sum(pg_column_size(eav_ugh)) FROM eav_ugh;
sum
--------
164997
(1 row)
regress=> SELECT sum(pg_column_size(no_null_cols)) FROM no_null_cols;
sum
--------
164997
(1 row)
Trong trường hợp này, bitmap rỗng hoàn toàn không thêm bất kỳ khoảng trống nào, có thể là do các yêu cầu về căn chỉnh.