mysql 外键_为什么大多数互联网公司不用外键约束
是否使用外鍵約束
【強(qiáng)制】不得使用外鍵與級(jí)聯(lián),一切外鍵概念必須在應(yīng)用層解決.-《阿里Java規(guī)范》
首先外鍵(Foreign Key)是什么東西
使用方案
假設(shè)有一個(gè)score表 id是自增id,score是分?jǐn)?shù),student_id是學(xué)號(hào)。
另一個(gè)student表,id是自增id,name是名字,student_id是學(xué)號(hào)。
那么設(shè)計(jì)這個(gè)的時(shí)候就希望有一個(gè)關(guān)聯(lián)關(guān)系,讓score的student_id指向student表的student_id,存在一個(gè)學(xué)生對(duì)應(yīng)多個(gè)成績(jī)的關(guān)系。所以我可以使用以下SQL語(yǔ)句
ALTER TABLE score ADD CONSTRAINT FOREIGN KEY (student_id) REFERENCES student(student_id);創(chuàng)建一個(gè)外鍵索引完成這個(gè)規(guī)則
完成后的表關(guān)系如下
外鍵原理
被指向的字段,具有唯一性
可以保證成績(jī)字段的一致性,即每一次插入一個(gè)score數(shù)據(jù),首先要檢測(cè)是否student表存在這個(gè)id,保證一致性
如果在外鍵類型上使用CASCADE,則會(huì)保證在做更新和刪除sutudent表的student_id時(shí),觸發(fā)一次級(jí)聯(lián)操作,會(huì)同步更新score表的student_id或者刪除student_id.
外鍵類型RESTRICT 也同樣會(huì)做一次檢測(cè),但不會(huì)做級(jí)聯(lián)操作,而是直接拒絕操作。
場(chǎng)景思考
知道外鍵是什么后,我們來(lái)思考一個(gè)場(chǎng)景:
現(xiàn)在有一個(gè)電商系統(tǒng),用戶有一個(gè)賬戶id,商品有一個(gè)商品id,這兩個(gè)字段和訂單綁定,此時(shí)訂單id和賬戶表ID構(gòu)成一個(gè)外鍵關(guān)系,同時(shí)和商品表id也構(gòu)成一個(gè)外鍵關(guān)系,那么我每次生成一筆訂單,就需要向另外兩張表查詢檢測(cè)一次數(shù)據(jù),那么就存在幾個(gè)問(wèn)題:
- 增刪改觸發(fā)這個(gè)查詢操作的性能消耗,服務(wù)器系統(tǒng)是否允許
- 在其他表查詢會(huì)上需要對(duì)其他表做一個(gè)內(nèi)部鎖,是否存在高并發(fā)死鎖情況
- 數(shù)據(jù)一致性全部交給數(shù)據(jù)庫(kù)服務(wù)器,數(shù)據(jù)庫(kù)服務(wù)器是否能夠承受
這些問(wèn)題在互聯(lián)網(wǎng)公司會(huì)顯得格外嚴(yán)重,因?yàn)樵L問(wèn)流量大的時(shí)候以上問(wèn)題基本上是完全無(wú)法得到MySQL系統(tǒng)本身解決的
同時(shí)在做分庫(kù)分表設(shè)計(jì)的時(shí)候,外鍵約束就會(huì)顯得格外離譜。
同時(shí)MySQL系統(tǒng)的外鍵設(shè)計(jì)是背離部分SQL標(biāo)準(zhǔn)的
引用自博客園Eden: (https://www.cnblogs.com/discuss/articles/1862244.html)
對(duì)SQL標(biāo)準(zhǔn)的背離:如果ON UPDATE CASCADE或ON UPDATE SET NULL遞歸更新相同的表,之前在級(jí)聯(lián)過(guò)程中該表一被更新過(guò),它就象RESTRICT一樣動(dòng)作。這意味著你不能使用自引用ON UPDATE CASCADE或者ON UPDATE SET NULL操作。這將阻止級(jí)聯(lián)更新導(dǎo)致的無(wú)限循環(huán)。另一方面,一個(gè)自引用的ON DELETE SET NULL是有可能的,就像一個(gè)自引用ON DELETE CASCADE一樣。級(jí)聯(lián)操作不可以被嵌套超過(guò)15層深。對(duì)SQL標(biāo)準(zhǔn)的背離: 類似一般的MySQL,在一個(gè)插入,刪除或更新許多行的SQL語(yǔ)句內(nèi),InnoDB逐行檢查UNIQUE和FOREIGN KEY約束。按照SQL的標(biāo)準(zhǔn),默認(rèn)的行為應(yīng)被延遲檢查,即約束僅在整個(gè)SQL語(yǔ)句被處理之后才被檢查。直到InnoDB實(shí)現(xiàn)延遲的約束檢查之前,一些事情是不可能的,比如刪除一個(gè)通過(guò)外鍵參考到自身的記錄。處理
因?yàn)橐陨蠁?wèn)題,我們通常在建模時(shí)隱性設(shè)計(jì)外鍵約束,實(shí)際實(shí)現(xiàn)采用業(yè)務(wù)邏輯模擬外鍵的方式處理,這樣可以解決把一致性全部放在DBA上的性能問(wèn)題,同時(shí)我們可以采用允許臟數(shù)據(jù)存在,然后定時(shí)數(shù)據(jù)清理的方案去保證數(shù)據(jù)處理的分時(shí)性能,避免高峰處理。
這樣的好處:
- 解決性能問(wèn)題
- 增加了可擴(kuò)展性,框架遷移不用在數(shù)據(jù)庫(kù)系統(tǒng)內(nèi)部實(shí)現(xiàn)邏輯約束
- 分庫(kù)分表的時(shí)候方便
- 不會(huì)在DB層面造成死鎖
反推:是否可以使用外鍵約束
我覺(jué)得在部分業(yè)務(wù)場(chǎng)景下是可以考慮使用的,回到最開(kāi)始的例子,教務(wù)系統(tǒng)的成績(jī)模塊重要的點(diǎn)不再是性能問(wèn)題,而是高可靠,因?yàn)閷?duì)學(xué)校來(lái)說(shuō),系統(tǒng)存在以下特點(diǎn):
- 數(shù)據(jù)量較少,一個(gè)學(xué)校學(xué)生最多不超過(guò)10萬(wàn)人,通常在5000-50000這個(gè)區(qū)間內(nèi),對(duì)DB來(lái)說(shuō)這是一個(gè)很小的數(shù)據(jù)量
- 數(shù)據(jù)不容許出錯(cuò),因?yàn)槌煽?jī)和學(xué)生的人身利益直接掛鉤
- 能夠進(jìn)行數(shù)據(jù)修改操作的用戶極少,只有教務(wù)處錄入成績(jī)的老師。
- 如果放在業(yè)務(wù)部分,如果出現(xiàn)student表student_id在第一次被刪除后,未清理score表數(shù)據(jù),這個(gè)student_id短時(shí)間內(nèi)被再次使用,而沒(méi)有做數(shù)據(jù)清理,就容易出現(xiàn)成績(jī)復(fù)用錯(cuò)誤,諸如此類
所以 不得使用外鍵與級(jí)聯(lián),一切外鍵概念必須在應(yīng)用層解決。 大部分情況下正確,但同樣我認(rèn)為需要分業(yè)務(wù)場(chǎng)景解決,并不能一竿子打死。
來(lái)源:為什么大多數(shù)互聯(lián)網(wǎng)公司不用外鍵約束 - JethroYu - 博客園
總結(jié)
以上是生活随笔為你收集整理的mysql 外键_为什么大多数互联网公司不用外键约束的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Matlab计算速度优化(矩阵,bsxf
- 下一篇: linux cmake编译源码,linu