2012-04-09 56 views
3

我正在重新設計一個包含大約1,500列的表的MySQL數據庫以及其他表。我們希望通過創建第二個表來對這個表中的數據進行規範化處理,第二個表對於初始表中存在的每一列/行都有一個記錄。我們稱這些表爲Master和MasterData。 Master將包含該表中所有記錄所需的基本信息。 MasterData將包含與主表中的記錄有關的一些附加數據的值。所以我們可以說法師會是這樣的:如何正確查詢規範化數據庫

MasterID  Property1  Property2 
1   Yes   No 
2   No   Yes 
3   Yes   Yes 
4   No   No 

比方說MasterData看起來就像這樣:

MasterID  Property  Value 
1   Property3 Yes 
1   Property4 No 
3   Property3 No 
4   Property7 Yes 

隨着我這麼遠嗎?如何查詢這些數據,並且每匹配主行只有一行返回,並且包含所有相關的MasterData信息。我搜索並找到了一些例子,但是他們花了很長時間來執行我們的數據。我已經根據前面提到的一個巨大表格中的現有數據創建了一個測試MasterData表。這導致MasterData擁有大約450萬條記錄,並且以下查詢執行和超時時間過長。

SELECT Property1, Property2, Master.MasterID, 
    GROUP_CONCAT(case when Property = "Property3" then Value end) as Property3, 
    GROUP_CONCAT(case when Property = "Property7" then Value end) as Property7 
FROM Master LEFT JOIN MasterData USING (MasterID) GROUP BY MasterID 
HAVING Property3='Yes' OR Property7='Yes'; 

Select * FROM Master AS M, MasterData AS MD1, MasterData AS MD2 
WHERE M.MasterID=MD1.MasterID AND MD1.Property='Property3' AND MD1.Value='Yes' 
AND M.MasterID=MD2.MasterID AND MD2.VAR='Property7' AND MD2.Value='Yes'; 

同樣,我們的目標是能夠獲取所有數據MasterData在一排,好像它是在主柱。這可能嗎?

任何幫助非常感謝!

+0

我寧願第一個查詢(儘管不是隱式連接語法),儘管我寧願不使用EAV表就像你在做什麼(有一些固有的問題)。雖然1500列是太多了。這些數據的範圍是什麼?你可能有更多的多列表,而不是迄今爲止顯示的內容。 – 2012-04-09 20:23:14

+0

你能指定用例嗎?我真的很想知道這種方法應該解決哪個問題。 – PepperBob 2012-04-09 20:33:12

+2

這不是標準化設計,只是你知道的。查詢效率也不高,也不容易。 – HLGEM 2012-04-09 20:47:10

回答

2

此外,我們的目標是能夠在MasterData中檢索一行中的所有數據,就像它是Master中的一列一樣。這可能嗎?

沒有完全理解你的目標,我要出去的肢體,並說這可能可能,嚴格地說。但在任何實際意義上都不太可能。即使是最好的情況下,性能也可能會很糟糕(只有一兩個屬性);在可能的情況下(30到500個屬性之間),你可能完全取下服務器。

標準化的並不意味着「創建第二個表格,該表格對於初始表格中存在的每一列/行都有記錄」。這並不意味着什麼,即使是遠程那樣。但它的可能規範化將實際上解決您的問題。 (根據我的經驗,大部分數據庫問題都是結構性的。)

您在這裏提出的解決方案對於您尚未說明的問題效果不佳。爲了充分利用StackOverflow的專業知識,請說明您嘗試解決的問題以及您嘗試的解決方案。

Wikipedia article about database normalization


如果你開始像這樣的表。 。 。

create table master_data (
    master_id integer not null, 
    property_name varchar(30) not null, 
    property_value boolean not null default true, 
    primary key (master_id, property_name) 
); 

insert into master_data values 
(1, 'Property3', true), 
(1, 'Property4', false), 
(3, 'Property3', false), 
(4, 'Property7', true); 

。 。 。那麼你可以通過一個簡單的查詢獲得所有事物的所有屬性。 (假設你的所有屬性都是布爾值。)

select * 
from master_data 
order by master_id, property_name 
-- 
1 Property3 t 
1 Property4 f 
3 Property3 f 
4 Property7 t 

應用程序代碼可以很簡單地循環。你也許可以刪除property_value爲false的所有行。

此結構允許爲每件事物提供無限數量的屬性。但是你的要求是a)在單行中返回任意數量的屬性,並且b)對應用程序代碼的最小改變必須改變。這是沒有辦法的。


如果你的表包含這些行。 。 。

insert into master_data values 
(1, 'Property3', true), 
(1, 'Property4', false), 
(3, 'Property3', false), 
(4, 'Property7', true), 
(1, 'Property7', true); 

這裏得到了一套「東西」有資格,並加入該集合到主數據的表的一種方式。

select md.* 
from master_data md 
inner join (select master_id 
      from master_data 
      where (
       (property_name = 'Property3' and property_value = true) or 
       (property_name = 'Property7' and property_value = true) 
      ) 
      group by master_id 
      having count(*) = 2) cd 
    on (md.master_id = cd.master_id) 

對於它的價值,標準化仍然是可能長期維護和性能最好的選擇。這種結構(上面)沒有標準化;對於大量數據,性能一般很差。 (PostgreSQL與可選的hstore模塊可能比MySQL更好)

+0

這是我在Stackoverflow上的第一篇文章,我不太確定評論的工作方式,但我會重複剛纔寫的內容。我們的問題是我們的Master表中沒有列(屬性),需要一種方法來繼續添加'屬性'。做這個的最好方式是什麼?我明白這不是'正常化'的定義,但我之前看到過這種技術用於電子商務網絡應用程序,所以我們認爲我們會在這裏嘗試。我絕對接受任何其他你可能有的建議或你可以指向我的鏈接。 – mrceolla 2012-04-10 17:01:47

+0

[MySQL具有列和行大小限制。](http://dev.mysql.com/doc/refman/5.0/en/column-count-limit.html)AFAIK,沒有SQL dbms支持不斷添加列。你*可能*能夠添加具有基本相同的結構和完全相同的主鍵數據類型(不是自動編號,但)的另一個表,並將它們與外鍵約束(使用INNODB,而不使用MyISAM)鏈接。這會給你一堆你可以在第二張表中使用的列,但我認爲這是一個創可貼,而不是解決方案。 (儘管在運行時加入兩個表;不要超出列或行的大小限制。) – 2012-04-10 17:26:50

+0

同意。我認爲類似結構的第二張桌子將是一種創可貼。我們可能會在第二張桌子上出現一個列限制,這個問題會再次出現,然後我們必須進入代碼並再次調整所有查詢。你能想到這個問題的「解決方案」嗎?有什麼我可以進一步解釋? – mrceolla 2012-04-10 19:52:13