一、mysql讓一個文章對應(yīng)多個tag的設(shè)計方法
要讓一篇文章可以對應(yīng)多個tag,通常需要設(shè)計一個多對多的關(guān)系,這可以通過引入一個中間表來實現(xiàn)。
具體來說,將文章和標(biāo)簽分別看作兩個實體,通過一個中間表來建立它們之間的多對多關(guān)系。中間表包含兩個外鍵,分別指向文章和標(biāo)簽表中對應(yīng)的記錄。每當(dāng)一篇文章與一個或多個標(biāo)簽產(chǎn)生關(guān)聯(lián)時,就在中間表中插入相應(yīng)的記錄,同時記錄對應(yīng)的文章ID和標(biāo)簽ID。
這樣設(shè)計的好處是,可以輕松地查詢某個標(biāo)簽下的所有文章,也可以方便地查找某篇文章所對應(yīng)的所有標(biāo)簽。如果需要添加或刪除文章與標(biāo)簽之間的關(guān)系,只需在中間表中插入或刪除記錄即可,不會對文章或標(biāo)簽本身造成影響。
以下是一個簡單的MySQL代碼示例:
CREATE TABLE articles ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(100) NOT NULL, content TEXT NOT NULL, PRIMARY KEY (id));CREATE TABLE tags ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, PRIMARY KEY (id));CREATE TABLE article_tags ( article_id INT NOT NULL, tag_id INT NOT NULL, FOREIGN KEY (article_id) REFERENCES articles(id), FOREIGN KEY (tag_id) REFERENCES tags(id));
其中:
articles表:存儲文章的基本信息;tags表:存儲標(biāo)簽的名稱;article_tags表:作為中間表,建立文章和標(biāo)簽之間的多對多關(guān)系。二、3種高效的Tags標(biāo)簽系統(tǒng)數(shù)據(jù)庫設(shè)計方案
目前主流的博客系統(tǒng)、CMS都會有一個TAG標(biāo)簽系統(tǒng),不僅可以讓內(nèi)容鏈接的結(jié)構(gòu)化增強(qiáng),而且可以讓文章根據(jù)Tag來區(qū)分。相比傳統(tǒng)老式的Keyword模式,這種Tag模式可以單獨的設(shè)計一個Map的映射表來增加系統(tǒng)的負(fù)載和查詢的效率。
1、數(shù)據(jù)庫設(shè)計方案1
此方案分為2個表:
Tag表文章表Tag表表結(jié)構(gòu)代碼如下:
tagid # tag標(biāo)簽的ID
tagname #tag內(nèi)容
num #當(dāng)前Tag的引用個數(shù)
文章表結(jié)構(gòu)代碼如下:
ID #文章ID
title #文章標(biāo)題
tags #tags列表,多個以,分割
tagid #tags的ID 多個以,分割
…
此種方式Tag標(biāo)簽主要內(nèi)容保存在文章表中,對于Tag表的壓力較小,只是添加的時候更新一下Tag的引用數(shù)量,但是查詢的時候效率不足,不是好辦法。
2、數(shù)據(jù)庫設(shè)計方案2
第二種方案使用2個Tag表,其中一個保存Tag信息,另一個保存映射信息:
Tag表代碼如下:
tagid # tag標(biāo)簽的ID
tagname #tag內(nèi)容
num #當(dāng)前Tag的引用個數(shù)
Tagmap表代碼如下:
tagid
aid
文章表代碼如下:
ID #文章ID
title #文章標(biāo)題
tags #tags列表,多個以,分割
…
這種形式,每次發(fā)布內(nèi)容和修改內(nèi)容的時候都去更新一下Tag表和 Tagmap表。查詢的時候需要從Tagmap表中查找響應(yīng)的文章ID,然后使用文章ID去查詢具體的文章信息,因為每次查詢都是使用索引,所以效率較高。
3、數(shù)據(jù)庫設(shè)計方案3
前兩種方案都是使用純粹的Mysql來設(shè)計的,第三種方案將使用Nosql的魅力來設(shè)計。基本結(jié)構(gòu)同方案2,只是在Tag表和Tagmap表中使用mongo/redis這樣的nosql數(shù)據(jù)庫服務(wù)器,這樣可以發(fā)揮nosql數(shù)據(jù)庫強(qiáng)大的線性查詢能力。
三、MySQL數(shù)據(jù)庫設(shè)計規(guī)范
1、數(shù)據(jù)命名規(guī)范
所有數(shù)據(jù)庫對象名稱必須使用小寫字母并用下劃線分割。所有數(shù)據(jù)庫對象名稱禁止使用 MySQL 保留關(guān)鍵字(如果表名中包含關(guān)鍵字查詢時,需要將其用單引號括起來)。數(shù)據(jù)庫對象的命名要能做到見名識意,并且最后不要超過 32 個字符。臨時庫表必須以 tmp?為前綴并以日期為后綴,備份表必須以 bak?為前綴并以日期 (時間戳) 為后綴。所有存儲相同數(shù)據(jù)的列名和列類型必須一致(一般作為關(guān)聯(lián)列,如果查詢時關(guān)聯(lián)列類型不一致會自動進(jìn)行數(shù)據(jù)類型隱式轉(zhuǎn)換,會造成列上的索引失效,導(dǎo)致查詢效率降低)。2、數(shù)據(jù)庫基本設(shè)計規(guī)范
所有表必須使用 InnoDB 存儲引擎:沒有特殊要求(即 InnoDB 無法滿足的功能如:列存儲,存儲空間數(shù)據(jù)等)的情況下,所有表必須使用 InnoDB 存儲引擎 MySQL 5.5 之前默認(rèn)使用 Myisam,5.6 以后默認(rèn)的為 InnoDBInnoDB 支持事務(wù),支持行級鎖,更好的恢復(fù)性,高并發(fā)下性能更好。數(shù)據(jù)庫和表的字符集統(tǒng)一使用 UTF8MB4:兼容性更好,統(tǒng)一字符集可以避免由于字符集轉(zhuǎn)換產(chǎn)生的亂碼,不同的字符集進(jìn)行比較前需要進(jìn)行轉(zhuǎn)換會造成索引失效。所有表和字段都需要添加注釋:使用 comment 從句添加表和列的備注,從一開始就進(jìn)行數(shù)據(jù)字典的維護(hù)。盡量控制單表數(shù)據(jù)量的大小,建議控制在 500 萬以內(nèi):500 萬并不是 MySQL 數(shù)據(jù)庫的限制,過大會造成修改表結(jié)構(gòu)、備份、恢復(fù)都會有很大的問題,可以用歷史數(shù)據(jù)歸檔(應(yīng)用于日志數(shù)據(jù)),分庫分表(應(yīng)用于業(yè)務(wù)數(shù)據(jù))等手段來控制數(shù)據(jù)量大小。謹(jǐn)慎使用 MySQL 分區(qū)表:分區(qū)表在物理上表現(xiàn)為多個文件,在邏輯上表現(xiàn)為一個表。謹(jǐn)慎選擇分區(qū)鍵,跨分區(qū)查詢效率可能更低。建議采用物理分表的方式管理大數(shù)據(jù)。盡量做到冷熱數(shù)據(jù)分離,減小表的寬度:MySQL 限制每個表非常多存儲 4096 列,并且每一行數(shù)據(jù)的大小不能超過 65535 字節(jié)。減少磁盤 IO,保證熱數(shù)據(jù)的內(nèi)存緩存命中率(表越寬,把表裝載進(jìn)內(nèi)存緩沖池時所占用的內(nèi)存也就越大,也會消耗更多的 IO)。更有效的利用緩存,避免讀入無用的冷數(shù)據(jù)。經(jīng)常一起使用的列放到一個表中(避免更多的關(guān)聯(lián)操作)。禁止在表中建立預(yù)留字段:預(yù)留字段的命名很難做到見名識義。預(yù)留字段無法確認(rèn)存儲的數(shù)據(jù)類型,所以無法選擇合適的類型。對預(yù)留字段類型的修改,會對表進(jìn)行鎖定。禁止在數(shù)據(jù)庫中存儲圖片,文件等大的二進(jìn)制數(shù)據(jù):通常文件很大,會短時間內(nèi)造成數(shù)據(jù)量快速增長,數(shù)據(jù)庫進(jìn)行數(shù)據(jù)庫讀取時,通常會進(jìn)行大量的隨機(jī) IO 操作,文件很大時,IO 操作很耗時。通常存儲于文件服務(wù)器,數(shù)據(jù)庫只存儲文件地址信息。延伸閱讀1:MySQL是什么
MySQL是一個關(guān)系型數(shù)據(jù)庫管理系統(tǒng),由瑞典MySQL AB 公司開發(fā),屬于 Oracle 旗下產(chǎn)品。MySQL 是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,在 WEB 應(yīng)用方面,MySQL是較好的 RDBMS(Relational Database Management System,關(guān)系數(shù)據(jù)庫管理系統(tǒng))應(yīng)用軟件之一。