2010-11-07 35 views
6

假設我有一個包含三列的大表:「user_name」,「user_property」,「value_of_property」。拉特也假設我有很多用戶(比方說100 000)和很多屬性(比如說10 000)。然後桌子將是巨大的(10億行)。我可以通過將一張大桌子分成許多小桌子來優化我的數據庫嗎?

當我從表中提取信息時,我總是需要關於特定用戶的信息。所以,我使用,例如where user_name='Albert Gates'。所以,每次mysql服務器需要分析10億行來查找那些包含「Albert Gates」作爲user_name的行。

把大桌子拆分成許多與固定用戶相對應的小桌子不是明智之舉嗎?

+0

您所描述的內容稱爲分區。在數據庫中,您可以設計圍繞數據的可瀏覽結構。您設置硬件來管理這類問題。我相信part​​tioning(這是你正在談論的sql服務器術語)是一個不在mysql中的功能 - 或者它不是7年前當我切換到sql server - 我知道它支持它。 – 2010-11-07 11:23:16

+0

@John Nicholas:http://dev.mysql.com/doc/refman/5.1/en/partitioning.html – 2010-11-07 11:26:48

+0

coool tyvm;)mysql確實有分區 – 2010-11-07 13:19:53

回答

5

不,我不認爲這是個好主意。更好的方法是在user_name列上輸入add an index - 或者查找(user_name, user_property)上的另一個索引來查找單個屬性。然後數據庫不需要掃描所有的行 - 它只需要在存儲在B-Tree中的索引中找到適當的條目,從而很容易在很短的時間內找到記錄。

如果您的應用程序仍然很慢,即使正確編制索引後,它有時也可能是您的最大表格partition的好主意。

您可以考慮的另一件事是規範化您的數據庫,以便將user_name存儲在單獨的表中並在其位置使用整數foriegn鍵。這可以減少存儲要求並可以提高性能。這同樣適用於user_property

+0

正常化user_name並在其他表中使用其id的另一個好處是,如果需要更改它,則不必更新潛在數千個記錄及其所有關係。 – 2010-11-07 14:01:33

3

你應該正常化您設計如下:

drop table if exists users; 
create table users 
(
user_id int unsigned not null auto_increment primary key, 
username varbinary(32) unique not null 
) 
engine=innodb; 

drop table if exists properties; 
create table properties 
(
property_id smallint unsigned not null auto_increment primary key, 
name varchar(255) unique not null 
) 
engine=innodb; 

drop table if exists user_property_values; 
create table user_property_values 
(
user_id int unsigned not null, 
property_id smallint unsigned not null, 
value varchar(255) not null, 
primary key (user_id, property_id), 
key (property_id) 
) 
engine=innodb; 

insert into users (username) values ('f00'),('bar'),('alpha'),('beta'); 

insert into properties (name) values ('age'),('gender'); 

insert into user_property_values values 
(1,1,'30'),(1,2,'Male'), 
(2,1,'24'),(2,2,'Female'), 
(3,1,'18'), 
(4,1,'26'),(4,2,'Male'); 

從性能的角度來看,InnoDB的聚集索引工程奇蹟在這個類似的例子(COLD RUN):

select count(*) from product 
count(*) 
======== 
1,000,000 (1M) 

select count(*) from category 
count(*) 
======== 
250,000 (500K) 

select count(*) from product_category 
count(*) 
======== 
125,431,192 (125M) 

select 
c.*, 
p.* 
from 
product_category pc 
inner join category c on pc.cat_id = c.cat_id 
inner join product p on pc.prod_id = p.prod_id 
where 
pc.cat_id = 1001; 
0:00:00.030: Query OK (0.03 secs) 
+0

請評論,如果你投票否則你只是表明你的無知。 – 2010-11-07 13:49:58

+0

我不認爲你已經規範化了任何東西。什麼已經規範化?歸一化的順序是什麼?什麼重複的數據已被消除?另外(這是挑剔的,我很抱歉)你要在哪裏存儲房產的價值?你真的想要這些物業有多麼多的關係嗎?目前,每個屬性可以在多個用戶之間共享,並且很難擁有所需的屬性。 – 2010-11-07 13:50:35

+0

抱歉,我在刪除它時反映出來。 – 2010-11-07 13:51:16

1

你爲什麼需要有這個表結構。我的問題在於,每當你想使用它時,你都必須將數據轉換爲屬性值。這在我看來是不好的 - 也存儲數字,因爲文本是瘋狂的,因爲它的所有二進制文件都是。例如,你將如何有必要的領域?還是需要基於其他字段限制的字段?例如開始和結束日期?

爲什麼不簡單地將屬性作爲字段而不是一些多對多的關係?

有1張桌子。當您的業務規則開始顯示屬性應該分組時,您可以考慮將它們移出到其他表中,並且與用戶表具有多個1:0-1的關係。但這不是標準化,並且由於額外的連接會略微降低性能(但是表名的自我記錄本質將極大地幫助任何開發人員)

我經常看到databqase性能的一種方式是完全閹割是通過通用

ID,屬性類型,屬性名稱,屬性值表。

這真的很懶,但非常靈活,但完全殺死性能。事實上,在一個表現糟糕的新工作中,我實際上問他們是否擁有這種結構的表 - 它總是成爲數據庫的中心點,並且速度很慢。關係數據庫設計的關鍵在於關係是提前確定的。這只是一種旨在以巨大的成本加快開發速度的技術。它還使應用程序層中的業務邏輯非常依賴行爲 - 這根本不是防禦。最終你會發現你想在一個關鍵關係中使用屬性,這會導致連接上的所有類型的連接,這進一步降低了性能。

如果數據與實體的關係爲1:1,則它應該是同一個表上的字段。如果您的桌子的寬度超過30個字段,請考慮將它們移到另一個表格中,但不要將其稱爲標準化,因爲它不是。這是一種技術,可幫助開發人員以性能爲代價將各個領域組合在一起,以幫助理解。

我不知道如果mysql有一個等效,但sqlserver 2008有稀疏列 - 空值不佔空間。 SParse column datatypes

我不是說一個EAV方法總是錯的,但我認爲使用關係數據庫這種方法可能不是最好的選擇。

2

正確編制索引數據庫將是提高性能的第一方法。我曾經有一個查詢花了半個小時(在一個大的數據集上,但沒有更少)。然後我們來發現這些表沒有索引。一旦建立索引,查詢花費的時間少於10秒。

相關問題