SQL反模式:实体-属性-值(EAV)问题(一)
? ? 但以下關(guān)系存在時(shí),可能會(huì)將數(shù)據(jù)設(shè)置成為EAV模式,比如一個(gè)問(wèn)題(Issue),可能有繼承它的bug和特性(FeatureRequest),他們的關(guān)系如下,引用AntiPatterns
針對(duì)上面的關(guān)系,如果考慮表格的列可能擴(kuò)展的情況,設(shè)計(jì)成EVA(Entity-Atrribute-Value)如下:
CREATE TABLE Issues (issue_id int PRIMARY KEY ); INSERT INTO Issues (issue_id) VALUES (1234); CREATE TABLE IssueAttributes ( issue_id BIGINT NOT NULL, attr_name VARCHAR(100) NOT NULL, attr_value VARCHAR(100), );通過(guò)IssueAttributes表,描述和報(bào)告日期通過(guò)attribute-value對(duì)的方式存儲(chǔ)起來(lái),如下:
INSERT INTO IssueAttributes (issue_id, attr_name, attr_value) VALUES (1234, 'product', '1'), (1234, 'date_reported', '2009-06-01'), (1234, 'status', 'NEW'), (1234, 'description', 'Saving does not work'), (1234, 'reported_by', 'Bill'), (1234, 'version_affected', '1.0'), (1234, 'severity', 'loss of functionality'), (1234, 'priority', 'high');上面的這種設(shè)計(jì),優(yōu)點(diǎn)在于,如果我想增加一個(gè)版本的列,可以直接插入一條記錄即可,不需要增加一列。但是EAV模式,存在如下一些缺點(diǎn)。
1.不能精確定義數(shù)據(jù)類(lèi)型,比如date_reported,報(bào)告日期,由于各個(gè)國(guó)家和地區(qū)使用日期格式不盡相同,有些是2020-02-02,有些是2/6/2020等等,甚至有些格式無(wú)法轉(zhuǎn)成日期。這樣顯示和統(tǒng)計(jì)都會(huì)出錯(cuò),比如,如下SQL也能插入成功
INSERT INTO IssueAttributes (issue_id, attr_name, attr_value) VALUES (1234, 'date_reported', 'haha'),2.不能定義約束,使用EVA不能定義外鍵約束;
3.EAV模式中的attribute名稱(chēng)可能不能統(tǒng)一,比如有些插入的是'date_reported',而有些是'report_date',這樣無(wú)法使用SQL查詢(xún);
3.重構(gòu)查詢(xún)結(jié)果問(wèn)題
當(dāng)我們使用 SELECT * FROM IssueAttributes WHERE issue_id =1234;這樣語(yǔ)句查詢(xún)出結(jié)果以后,出現(xiàn)了多行,其實(shí)我們期望的結(jié)果是一行,然后把其他行轉(zhuǎn)化到列上去,盡管有些SQL已經(jīng)支持了行轉(zhuǎn)列了,但是這樣的SQL抬復(fù)雜,在不考慮行轉(zhuǎn)列的情況下,需要如下寫(xiě)SQL才可以達(dá)到一行,查詢(xún)多少列就需要關(guān)聯(lián)自身表多少次,降低了查詢(xún)效率。
SELECT i.issue_id, i1.attr_value AS "date_reported", i2.attr_value AS "status", i3.attr_value AS "priority", i4.attr_value AS "description" FROM Issues AS i LEFT OUTER JOIN IssueAttributes AS i1 ON i.issue_id = i1.issue_id AND i1.attr_name = 'date_reported' LEFT OUTER JOIN IssueAttributes AS i2 ON i.issue_id = i2.issue_id AND i2.attr_name = 'status' LEFT OUTER JOIN IssueAttributes AS i3 ON i.issue_id = i3.issue_id AND i3.attr_name = 'priority' LEFT OUTER JOIN IssueAttributes AS i4 ON i.issue_id = i4.issue_id AND i4.attr_name = 'description' WHERE i.issue_id = 1234;針對(duì)以上這些問(wèn)題,一般設(shè)計(jì)成EAV模式是想要數(shù)據(jù)庫(kù)更加靈活,但是這種模式更使用NoSQL數(shù)據(jù)庫(kù),比如使用MongoDB,下一篇文章,我們將介紹針對(duì)這種如何設(shè)計(jì)關(guān)系型的解決方案。
?
?
總結(jié)
以上是生活随笔為你收集整理的SQL反模式:实体-属性-值(EAV)问题(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CocosCreator实现不规则的点击
- 下一篇: 国际风筝节开幕 深圳大梅沙上演嫦娥奔月(