坦率地說,最好的選擇是 「不EAV」。考慮使用hstore
領域,XML
,或json
。
在PostgreSQL沒有性能優勢,使用每數據類型表。 NULL
值存儲在一個緊湊的NULL
位圖中,所以它與你是否有像(NULL, NULL, NULL, 42, NULL, NULL)
或(42)
這樣的元組沒有多大區別。
這也允許你添加CHECK
約束實施,確切地說一個字段必須是非NULL
,所以你不會得到不同類型的多個值。
演示:
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)
在這種情況下,零位不會由於對齊要求增加任何空間可言,有可能。
糾正我,如果我錯了,但如果你發佈一個鏈接,說明*性能*原因magento使用類型特定的表..不是明顯的答案嗎?如果您不使用特定於類型的表格,則最終將所有內容添加到varchar/text列。如果你這樣做,你需要一個元數據表來解釋屬性的存儲位置(在int,float,char表中)。 –
@ N.B。感謝您的評論,但我也可以創建具有不同列的值表(value_int,value_datetime等)。我希望你能解釋爲什麼特定數據類型選項會帶來更好的性能,至少在Magento的情況下? – Hans
因爲如果使用特定於數據類型的表,並且可以將某些數據類型表編入索引,那麼將節省更多空間。這不是一個性能增益,因爲它可以放寬需要擔心屬性是否適合值列。想象一下,有一個EAV設計有1個值表,並且您正在存儲可以是單個1位數字或大量文本的數據。你被迫使用'text'類型,所以你可以存儲任何東西。或者你可以創建一個特定類型的表,不用擔心「全部捕捉」表,它是存儲值的列。 –