跳轉到

常見 Anti-pattern

使用方面

1. 把 RDBMS 用在 Inter-process communication

  • RDBMS 內有 REDO LOG,UNDO LOG,Lock Manager,都是為了維護資料的完整性和正確性。
  • 單純用來暫存 IPC 數據,會浪費 CPU 和 Storage IO
  • 最簡單的 IPC,可以使用 Redis 中的 List,進階的請用 rabbitMQ

2. 把 RDBMS 當作 logging server

  • log 是建立了便永不改動的數據,而且這些數據極少被單獨使用,一般都會經過 aggregation 用來產生報告
  • txt 檔案是 log 的理想存放位置

3. 在 Master 上產生報告

  • 應該在 read-only slave 上進行
  • 產生報告時會吃掉 Master 寶貴的 Storage IO,而且佔用寶貴的 Memory
  • 更大型系統,應該有專門用來做 Reporting 的資料庫(像是 Data Warehouse)

編程方面

1. SQL statement 超過 100 行

  • 會有報應的,請相信我
  • 太長的 statement,會讓 Query optimizer 無法有效工作
  • 應該把太長的 statement 改成多個步驟,每個步驟的結果用 temporary table 去暫存

2. 把系統邏輯放到 RDBMS 的 trigger

  • 除非正在 database refactoring,利用 trigger 作為一種暫時性手段
  • 應該把系統邏輯放到 application tier
  • 當出現了 bug 而引起資料錯誤,而你要在十分鐘內作緊急的資料更正,這些 trigger 會妨礙你的

3. 把所有的東西都寫在 application tier

  • data intensive / multiple steps 工作可以考慮用 stored procedure 來做

4. 在 stored procedure 中使用 loop

  • SQL 本身是 set-based 語言,請盡量使用 SQL 作 set operation

5. 在 stored procedure 中使用 recursion

  • 請考慮把工作放在 application tier

Schema 設計方面

1. 使用 auto-increment 作為 PK

  • 別害怕 ORM 層的麻煩,系統發生 blocking 時要花的氣力遠比 ORM 麻煩要多
  • 如果有 natural key,請優先使用,natural PK 有機會能用作 index skip scan
  • 真的不能用 natural key 時,請用 UUID

2. 為了報表而建立 index

  • index 會大幅影響 master 的 WRITE 效能
  • 報表能在 slave node 慢慢產生
  • 報表很多時候需要 range scan,secondary index 幫助不大

3. smart column

  • 1NF 的定義:所有 column 的 value 都必須是 atomic value
  • xml, json, array 這些東西全都違反 1NF
  • xml, json 內有過份高的自由性,未把 column value 內容拿出來前,永遠猜不到 column 內具體存了什麼東西
  • smart column 內部資料不能再建立 index,當報表要用上 smart column 內部資料作 filtering/joining 時,不但 Query 難寫,其效能也會低下
  • 空運貨物管制系統中,flight 這個 table 的 PK 不是 flight_no ,而是
  • 不是以<”BR892”> 作為 PK,而是<”BR”, “892”> 作為 PK
  • 系統想要找到長榮航空的所有航次時
  • 只需要 where airline_code = 'BR'
  • 而不是 where flight_no like 'BR%'

4. denormalization

  • 為了迴避 subquery 和 join,有人想進行 denormalization,故意地在一個 table 放進 multiple data model 的數據
  • 例子:因為用戶在檢查自己所買的機票時,頁面也會顯示航次出發時間/航次到達時間的資訊,因此做了 denormalization,在 ticket 這一個 table 中也存放了航次資訊
  • OLTP 的 denormalization 一般無助提升系統效能,反而大幅增加改動資料時的麻煩/出錯可能性
  • denormalization 讓 table schema 變得不再直覺
  • Documentation?你認真的嗎?
  • 三個月後,有多少人還記得自己以前做過的東西(特別是長期爆肝下)

5. 多用途 column

  • 你的系統是用來生產瑞士軍刀的嗎?
  • 分辦方法:系統需要知道這個 column /其他 column 的 value ,才知道怎麼去使用這個 column 的內容

Example

能讓用戶以 username/password 或是 facebook 身份登入的系統

有人建議反正用戶只會以單一的方式登入,所以 user 這個 table 只有一個 auth 的 column - 以 username 登入的用戶,auth 的內容是:username:<username>/<hashed_password> - 以 facebook 身份登入的用戶,auth 的內容是:facebook_id:<facebook_id> - 理由是這樣的做法可以只使用一個 column,也只有一個 secondary index

致命缺點

  • 這設計只能讓用戶以單一方法登入
  • 因為 hashed_password 是以 salt password 來計算的,這設計讓 index 失效
  • 如果要知道系統有多少 facebook 用戶,便需要 where auth like 'facebook_id%'

6. 多用途 table

  • 多用途 column 的進化版
  • 此 anti-pattern 一旦發生,系統必亡
  • 分辦方法:
  • 某一 table 內,大量 column 的 value 是 null
  • 這個 table 內有一個叫「type 」或是「kind 」的 column,application tier 需要先知道這個 column 的值才能決定這筆 record 怎麼使用

Example

某空運系統(如有雷同,實屬不幸)

  • 出境貨物和入境貨物都放到freight這個 table,然後 freight_type 這個 column,I 代表入境貨物,E 代表出境貨物
  • 結果某天某個 procedure 出錯,type 由 I 改成 E,引起全面性數據錯誤
  • 對於出境的系統流程,freight 當然只跟出境相關的 table join;入境時只跟入境相關的 table join
  • 結果,optimizer 對於這種擁有雙重性格的 table,常常使用了非最佳化的 execution plan