#7 系統上線了,我需要拿掉資料庫裡 foreign key 嗎?

前面講了一些基礎的內容,這篇文章來談談一些較實務面的經驗.

還記得許多年前在台北工作的時候,曾經在工作上發生一個經驗,當時我負責幫一個公司做一個小系統.這是一個簡單的小型商業系統,是一個 web application,在前端的部份分成兩項專案,其中一個專案是供給客戶登入各式各樣的資料,另一個專案是供管理者登入做資料的驗證與管理,而後端的部份是一個資料庫.在這個小專案裡,我負責前端客戶登入資料以及資料庫的設計,而管理者資料管理的部份是由該公司的工程師負責.

當整個專案在進行到後期的階段時,工程師們便開始為各項功能做驗證.在當時我並不清楚他們工程師負責的部份寫的如何,但是有件事情我倒是記得很清楚.某一天下午,該公司的工程師不知遇上了什麼技術上的問題,結果他們的主管就跑來找我,一付倚老賣老的姿態來跟我說話.這位主管說,我們過去做案子的情況都是這樣,當系統準備上線時都會把 foreign key 拿掉,以減少程式的執行時發生錯誤.老實說,我當時聽了他的說明,他只是要告訴我移除 foreign key 好讓他們那部份的程式不會出錯.當時我也沒深究他們工程師的程式是怎麼寫的,只是覺得奇怪.但畢竟那是他們的專案,既然他們都這樣要求了,所以就把資料庫裡相關的 foreign key 都移除了.

現在看看,你們公司是不是也會這樣呢 ? 是什麼原因造成你們會決定拿掉 foreign key 呢 ? Foreign Key 是維持資料一致性的其中一個方法,拿掉有什麼好處呢 ? 對資料庫引擎來說倒是變的比較輕鬆,因為某個欄位上如果有 foreign key 的限制,每當該欄位的資料在被修改時,資料庫引擎都得去檢查 foreign key 對應回去的那一個表格是不是有合法的資料存在.如果資料不存在的話,資料庫引擎就必須產生錯誤訊息.因為資料庫引擎做的事變少了,因此完成指令的時間將會變快,這樣聽起來好像蠻不賴的.但如果這麼不賴的話,何必要有 foreign key 的存在呢 ? 前面曾提到,foreign key 是維持資料一致性的其中一個方法.如果你把 foreign key 拿掉了,也就代表資料庫引擎不會為你檢查資料是否合法,所以如果程式撰寫或是邏輯上處理有問題時,就很容易造成幽靈資料.所謂的幽靈資料就是在 foreign key 的欄位上的資料在對應的 primary key 欄位上沒有這樣的資料,因此當你要做 table join 時,那些資料便不會被 join 起來.用一個簡單的例子來看: 資料庫中有兩個表格,第一個表格是客戶表格,第二個表格是訂單表格.客戶表格的 primary key 是 Customer ID,訂單表格的 primary key 是 Order ID,而這兩個表格有一個關聯就是透過 Customer ID 形成的,因此訂單表格的 Customer ID 就是客戶表格 Customer ID 的 foreign key.

Customer ID Customer Name
A1 客戶一
A2 客戶二

Order ID Customer ID
O1 A1
O2 A3

如果今天把這訂單表格 Customer ID 的 foreign key 拿掉之後,那就表示當你在新增或更新訂單表格時,Customer ID 並不會受到客戶表格的 Customer ID 所限制,因此就合法可以出現 A3 的客戶編號在訂單表格裡,但麻煩的是客戶表格裡沒有 A3 編號存在,所以訂單編號 O2 就變成了所謂的幽靈資料.

當然,以上是很簡單的例子,你覺得不可能發生,但如果專案夠大,開發的工程師比較多而且整個團隊沒有一個有紀律的開發方法時,當你把資料庫的 foreign key 拿掉,那麼發生幽靈資料的機率便會很高.這時候影嚮的可是整個專案的品質,甚至會影響到客戶的信任度.所以,到底該不該把 foreign key 拿掉,我能給的建議就是,應該是去查看為何程式會出錯,而不該把錯怪在 foreign key 上.只要 database schema 的設計是合理的,foreign key 就不應該出錯,而是程式的邏輯有問題.因此,我還是建議你別拿掉 foreign key,因為我覺得資料庫裡的資料一致性比拿掉 foreign key 所獲得的效能提升還來的重要.

Share: