| 導購 | 订阅 | 在线投稿
分享
 
 
 

在數據量和訪問量劇增條件下保持數據庫效率

來源:互聯網  2008-08-14 23:14:31  評論

在某些網站裏,你可以訂閱好友,這樣,好友發的消息就會出現在你的主頁裏,這種方式確實很人性化,但是就引出了一個疑問,他們應該如何組織數據庫才能在很大的數據量和訪問量下效率最高呢?

首先,數據庫應該是這樣的:(括號裏是字段,其他無關信息省略)

用戶表:user (uid, name), uid爲主鍵。

信息表:msg (mid, uid, content), mid爲主鍵,uid爲發貼人。

好友表:friend (uid, fid), uid爲主人,fid爲好友(即uid訂閱的人的id)。

這樣,要查詢出某人的所有好友的信息就可以這樣寫SQL語句:(已查詢uid=1的爲例)

1) SELECT * FROM msg, friend WHERE msg.uid=friend.fid AND friend.fid=1;

注意:千萬不要寫成:

2) SELECT * FROM msg WHERE uid IN (SELECT fid FROM friend WHERE uid=1);

子查詢的方法比級聯兩張表慢了不止1個數量級!

(測試結果,方法1)能在10-30ms查詢出結果,而方法2)則用了3min還沒有出來結果)

有些人在網上說再增加一張中介表可以提高速度:

中介表:linker (uid, mid)

中介表是這樣用的,每次當一個人發了一篇帖子,則將所有訂閱他的人(uid)和這篇帖子的mid插入中介表裏,例如,uid=1的人有3個訂閱者,分別爲:2、3、4,則當uid=1的人發了一篇帖子mid=100時,就應往linker表裏插入這些數據:(2, 100), (3, 100), (4, 100)。這樣,對一個uid而言,linker表和msg表就形成了一對一的關系。查詢的時候,只需級聯linker表和msg表就行了,如下:(還是以查uid=1的爲例)

3) SELECT * FROM msg, linker WHERE msg.mid=linker.mid and linker.uid=1;

這樣乍看好像比1)要快一些,因爲就一個uid而言linker表和msg表是一對一的關系,而方法1)的卻是一對多的關系。而且,有些人認爲,就算不這麽看,因爲方法3)在插入時比方法1)多做了很多操作,所以查詢的速度應該能比方法1)快,至少不會比方法1)慢。

我實際測試下來的結果是,方法3)比方法1)慢了至少1倍的時間,而且數據量越大,慢得就越多。測試結果:

a) user有10,000條,friend有160,000條,msg有80,000條時:平均查詢時間:

方法1)是:0.04s,方法3)是0.08s,3)比1)慢1倍。

b) 當msg有260,000條時:方法1)是:0.18s,方法3)是:0.70s,3)比1)慢3倍。

(以上結果都是在建了索引之後的)

根據分析,3)比1)慢的原因,主要是當數據增大時,linker表的數據量急劇增大所致。因爲當msg裏有260,000條數據是,linker表的數據量已經超過4,000,000條了。

通過對這個的研究得出幾點體會:

◆1、數據庫對where的優化做得太好了(除了"in"關鍵字)。

◆2、索引對數據查詢效率的影響是太大了,我開始測試的時候沒有建索引,查詢時間都在幾百毫米,建了以後降低到幾十毫米了。

◆3、不要隨便相信網上的一些討論,要通過自己學過的知識去驗證網上討論的對錯。

在某些網站裏,你可以訂閱好友,這樣,好友發的消息就會出現在你的主頁裏,這種方式確實很人性化,但是就引出了一個疑問,他們應該如何組織數據庫才能在很大的數據量和訪問量下效率最高呢? 首先,數據庫應該是這樣的:(括號裏是字段,其他無關信息省略) 用戶表:user (uid, name), uid爲主鍵。 信息表:msg (mid, uid, content), mid爲主鍵,uid爲發貼人。 好友表:friend (uid, fid), uid爲主人,fid爲好友(即uid訂閱的人的id)。 這樣,要查詢出某人的所有好友的信息就可以這樣寫SQL語句:(已查詢uid=1的爲例) 1) SELECT * FROM msg, friend WHERE msg.uid=friend.fid AND friend.fid=1; 注意:千萬不要寫成: 2) SELECT * FROM msg WHERE uid IN (SELECT fid FROM friend WHERE uid=1); 子查詢的方法比級聯兩張表慢了不止1個數量級! (測試結果,方法1)能在10-30ms查詢出結果,而方法2)則用了3min還沒有出來結果) 有些人在網上說再增加一張中介表可以提高速度: 中介表:linker (uid, mid) 中介表是這樣用的,每次當一個人發了一篇帖子,則將所有訂閱他的人(uid)和這篇帖子的mid插入中介表裏,例如,uid=1的人有3個訂閱者,分別爲:2、3、4,則當uid=1的人發了一篇帖子mid=100時,就應往linker表裏插入這些數據:(2, 100), (3, 100), (4, 100)。這樣,對一個uid而言,linker表和msg表就形成了一對一的關系。查詢的時候,只需級聯linker表和msg表就行了,如下:(還是以查uid=1的爲例) 3) SELECT * FROM msg, linker WHERE msg.mid=linker.mid and linker.uid=1; 這樣乍看好像比1)要快一些,因爲就一個uid而言linker表和msg表是一對一的關系,而方法1)的卻是一對多的關系。而且,有些人認爲,就算不這麽看,因爲方法3)在插入時比方法1)多做了很多操作,所以查詢的速度應該能比方法1)快,至少不會比方法1)慢。 我實際測試下來的結果是,方法3)比方法1)慢了至少1倍的時間,而且數據量越大,慢得就越多。測試結果: a) user有10,000條,friend有160,000條,msg有80,000條時:平均查詢時間: 方法1)是:0.04s,方法3)是0.08s,3)比1)慢1倍。 b) 當msg有260,000條時:方法1)是:0.18s,方法3)是:0.70s,3)比1)慢3倍。 (以上結果都是在建了索引之後的) 根據分析,3)比1)慢的原因,主要是當數據增大時,linker表的數據量急劇增大所致。因爲當msg裏有260,000條數據是,linker表的數據量已經超過4,000,000條了。 通過對這個的研究得出幾點體會: ◆1、數據庫對where的優化做得太好了(除了"in"關鍵字)。 ◆2、索引對數據查詢效率的影響是太大了,我開始測試的時候沒有建索引,查詢時間都在幾百毫米,建了以後降低到幾十毫米了。 ◆3、不要隨便相信網上的一些討論,要通過自己學過的知識去驗證網上討論的對錯。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有