mysql web數據庫的設計歸範-2表設計原則

[職責分離原則]mysql

職責分離原則是指在設計的時候應當考慮到數據的產生,聚合使用等原則,每一個系統幹本身能幹的事情,每一個系統只幹本身的事情。一個數據表應該放在哪一個系統中,一般取決於幾點:web

1. 誰產生這個信息:一般狀況下誰產生了這個數據應當對此數據負責;也就是考慮該數據的建立,發展,銷燬等全生命週期的定義,並將這個定義維護起來提供給消費者做爲消費原則;sql

2. 誰最常用這個信息:若是某個系統最常用這個數據,最常常去修改某個數據,也應該由該系統來負責保存維護該數據;數據庫

3. 遵照高內聚,低耦合的考慮:在存放數據的時候若是考慮到數據使用原則致使了相關度很是高的數據存放在多個地方,須要多個系統來維護這個數據就有可能致使系統間的耦合性加強,應當儘可能避免。異步

在咱們設計數據庫表間的關係的時候也應當遵照相同原則,職責分離下降耦合,但同時要考慮到性能狀況,作到適當冗餘而不致使修改邏輯複雜。數據庫設計

舉個最多見貼子與評論的例子:post

CREATE TABLE `wanted_post` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `puid` int(10) unsigned NOT NULL,
  `user_id` int(10) NOT NULL COMMENT '發貼用戶的id',
  `username` varchar(50) NOT NULL COMMENT '發貼用戶的用戶名',
  `city` smallint(4) NOT NULL COMMENT '所在城市',
  `ip` bigint(14) NOT NULL COMMENT '發帖人的ip',
  `district_id` tinyint(2) NOT NULL COMMENT '所在區域的id',
  `district_name` varchar(20) NOT NULL COMMENT '行政區名字',
  `street_id` tinyint(2) NOT NULL COMMENT '所在街道(地標)的id',
  `street_name` varchar(20) NOT NULL COMMENT '小區名字',
  `title` varchar(255) NOT NULL COMMENT '帖子的標題',
  `description` text NOT NULL COMMENT '帖子詳情描述',
  `post_at` int(11) NOT NULL COMMENT '用戶發帖時間,數據建立的時間,使用整型存儲',
  `refresh_at` int(11) NOT NULL COMMENT '帖子被修改的時間,整型存儲',
  `show_time` int(11) NOT NULL COMMENT '帖子顯示時間',
  `age_max` int(11) NOT NULL DEFAULT '0' COMMENT '招聘最小年齡',
  `age_min` int(11) NOT NULL DEFAULT '0' COMMENT '招聘最大年齡',
  `post_refresh_at` int(11) NOT NULL COMMENT '刷新時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_puid` (`puid`),
  KEY `user_id_index` (`user_id`),
  KEY `post_at_index` (`post_at`),
  KEY `refresh_at_index` (`refresh_at`),
  KEY `show_time_index` (`show_time`)
) ENGINE=InnoDB AUTO_INCREMENT=55295 DEFAULT CHARSET=utf8 COMMENT='招聘帖子表'


CREATE TABLE `wanted_post_comment_99` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `puid` int(10) unsigned NOT NULL,
  `user_id` int(10) NOT NULL COMMENT '評論用戶ID',
  `post_at` int(11) NOT NULL COMMENT '評論時間',
  `detail` text NOT NULL COMMENT '評論詳情',
  PRIMARY KEY (`id`),
  KEY `user_id_index` (`user_id`),
  KEY `puidid_index` (`puid`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='招聘評論分表99'


因爲評論表數據量很大,在預先作好分表,按貼子puid分紅100張子表,那麼當前詳情頁涉及sql以下:
性能

select * from wanted_post where puid=xxxx;
select * from wanted_post_comment_99 where puid=xxxx;

這是一個簡化的模型,評論多了,還要涉及分頁,不可能一次性全取出來。對於上面的場景,嚴格尊守高內聚,低耦合的原則,不會存儲冗餘數據。相比較還有一種文檔型數據庫,例如mongo,就能夠將評論與貼子存放在一塊兒,訪問的時候只需一次順序IO操做。總體來說表設計,要按照職責劃分原則。
ui


[在線處理與分析分離]spa

1. 爲了保障線上數據處理的性能,將一些分析相關的數據及分析結果,應當使用單獨的庫來進行存儲,避免在數據分析的時候致使業務數據吞吐量降低,引發系統問題。

2. 專門用於存放離線報表數據,並提供線上數據查詢方法,建議將統計結果,彙總的數據都從在線處理數據庫中移走。



對於上面的wanted_post求職貼子表,在線處理只能是用戶在操做:瀏覽,修改,刪除,分別對應以下sql:

select * from wanted_post where puid=xxxxx;
update wanted_post set xxx=xxx where puid=xxxx;
delete from wanted_post where puid=xxxx;


一樣,對於後臺統計來說,都是些聚合操做,很是消耗性能,例如查看某一用戶發貼量:

select count(*) from wanted_post where user_id=xxxx;

上面舉個通用的例子,原則上要將在線用戶請求和後臺統計請求分開。簡單來說,對於這種需求處理以下:

  1. 將請求指向不一樣slave ,這種方法簡單高效,缺點是數據量增大就玩不轉。

  2. 創建離線報表庫,專門存放統計結果,這樣將計算與展現異步處理,缺點是對於實時業務響應很差。

  3. 實時拉取mysql row binlog,作數據的異構處理(tungsten, canal),將增量結果處理後(storm),保存在數據庫中,基本實時。


[事務與日誌分離]

用戶生成內容和用戶行爲日誌要分開,這一點很好理解,舉兩個例子:

  1. 遊戲DB裏存放玩家的基礎信息,裝備,屬性,好友列表等等,這些放到數據庫裏面。可是玩家的行爲日誌,好比消耗金幣,今天下過哪些副本,買過什麼頂級裝備,這些屬於行爲日誌,應該單獨存放並分析處理。 

  2. 對於web用記,有好多用戶置頂,刷新,競價,展現等行爲,要求實時而且量很大,必定要和貼子分開。

行爲日誌,須要作分析處理,而且因爲時效性不宜存儲在mysql中,後期維護就是地雷。


[歷史可追溯]

在數據庫設計的時候爲了保障數據是可追溯的,應當遵循一些簡單的約定,過後方便數據的查詢和統計:

1. 對於狀態數據,應當設計相應狀態的字段來保存該數據的最後狀態,同時記錄下來該數據的初始建立人,時間以及該數據的最後修改人和修改時間;因此在交易數據(如訂單合同),廣告數據,帳戶表等都應該默認有狀態(status),建立人(creator/creator_name),建立時間(created_at),最後修改人(modifier/modifier_name),最後修改時間(modified_at)等字段用來代表數據的當前狀態,建立信息及修改信息。

2. 針對須要跟蹤每次修改的數據,須要在數據發生變化的時候記錄一張日誌表,用於記錄該數據發生變化的全生命週期。針對只須要關注關鍵字段變化的狀況,則日誌表中只須要記錄關鍵字段變化便可,但操做人,操做類型,時間應當準確記錄,日誌表數據一旦生成不容許進行修改。如用戶帳戶的充值流水,消費流水都是一些業務緊相關的日誌。而審覈日誌,操做記錄等日誌則屬於與業務關聯較小的日誌。

3. 針對全部歷史須要保留的數據則須要每次變化都生成一個新的版本,好比類目信息等,對原始數據永遠只作insert操做,不作delete及update操做。但這種狀況僅限於極端數據歷史要求極高的狀況下使用。

相關文章
相關標籤/搜索