關於 RDBMS 的 Schema Migration...

在「NoSQL 大腸花」這份投影片裡面的 Page 12 有提到關於 RDBMS 的 Schema Migration:

以目前 open source 的兩個專案,MySQLPostgreSQL 來看,裡面提到的 lock 應該都不是問題...

首先是 MySQL 的部份,真的量大的網站都應該是往 InnoDB 投靠,而 pt-online-schema-change 在這個領域則是處理的很好。

Facebook 的 Mark Callaghan 曾經在 2010 年寫過一篇關於 InnoDB 的 online schema change 的原理:「Online Schema Change for MySQL」,主要是利用 Trigger 的機制,用七個步驟架構出沒有 downtime 的 online scheme change。

就算不考慮 pt-online-schema-change 這種工具,在 MySQL 5.6 開始,就有愈來愈多 ALTER TABLE 的行為是不會影響到 read/write 了:「Avoiding MySQL ALTER table downtime」。

而 PostgreSQL 的情況也差不多,常見的 ALTER TABLE (新增與刪除 column 與 index) 也都不會影響 read/write。

這些在 Stack Overflow 上有不少討論:「ALTER TABLE without locking the table?」。

MySQL 在 RDBMS 領域裡比起來的確是不怎樣,不過沒有這麼糟糕啊...

InnoDB 的 isolation mode

Percona 老大 Peter Zaitsev 寫了一篇關於 InnoDB 的 isolation mode 與效能的關係:「MySQL performance implications of InnoDB isolation modes」。

關於 isolation level 的介紹,也可以參考維基百科上的說明:「Isolation (database systems)」。

其中有個我也認同的的建議:

In general I think good practice is to use READ COMITTED isolation mode as default and change to REPEATABLE READ for those applications or transactions which require it.

需要 REPEATABLE READ 需求的 transaction 可以在 session 裡面開,不需要平常就開著。

而剛從 MyISAM 轉過去的因為本來就沒有 transaction,換到 InnoDB 時強烈建議就直接設上去 (剛好在註解也有提到):

I think READ-COMMITTED is better default yet it can break some applications. Though so changing to default storage engine from MyISAM to Innodb did.

資料結構、RDBMS、ORM

欠了很久的雜記。既然是雜記,只是把一些事情記錄下來,許多句子的主題會跳來跳去,請多見諒。

先解釋標題的三個詞彙。這邊要講的是三種存取資料的方式:

  • 資料結構:直接操作最底層的資料結構。
  • RDBMS (Relational Database Management System,關聯式資料庫):透過 RDBMS 存取資料的方式,在 open source 領域比較常遇到 MySQLPostgreSQL。由於與下面的 ORM 比較,這一條指的是透過 SQL query 去存取資料。
  • ORM (Object-Relational Mapping):透過程式語言的 object 以及 object 之間的關聯性存取資料。

彈性最高、效能也最好的是直接的資料存取,但寫起來也最複雜;而 ORM 大致上就是反過來。

現代的 RDBMS 大多都有實做 ACID,在自己操作資料結構時考慮這塊會比較辛苦。兩個層級之間有一些 library 試著解決這個問題 (像是 BerkeleyDB 或是 LevelDB),不過這篇文章暫時跳過。

MySQL 與其他的 RDBMS 比較起來欠了許多東西,但 High Availability 的成熟度以及效能而成為 open source 的第一選項。而也因為許多人使用,大家都知道 MySQL 的先天限制,也有許多 workaround 出現,所以大多數的狀況下這不是問題。

MySQL 的 InnoDB 其實寫的相當不錯,但 MySQL 的 SQL parser 一直都是 MySQL 的痛處,所以許多人使用 MySQL 時會儘量使用 simple query,而 ORM 的特性剛好可以搭上風。

使用 ORM 時最常見要避免的是 N+1 的問題,其他常見到的問題大多都不是 ORM 專有的。

先整理到這邊。

避免用 SQL 的 OFFSET 實做 Pager

發現以前沒有提到過...?

WordPress.com Developer Resources 寫的這篇「An efficient alternative to paging with SQL OFFSETs」提到了用 OFFSET 實做 Pager 的效率問題。

因為 RDBMS 是人寫的,所以人想不到的方法,程式也做不到,像是這樣的 SQL query 效率不會好:

SELECT * FROM my_table ORDER BY pk LIMIT 8000000, 100;

如果這是一般以 B+tree 儲存的 RDBMS (或是類似的資料結構),會先把 pk 拿出來,從最小的開始計算,掃過八百萬次後再去抓一百筆 pk 的值,最後再回到 my_table 內把所有資料拉出來。

這個方法當 offset 小的時候不會有感覺,但大了以後就會爆炸。就算 primary key 都在記憶體內,仍然是狂操 CPU L2/L3 以及記憶體的存取速度。

目前常見的分頁作法是在 url 上妥協,只提供「下一頁」或「下 n 頁」的功能。如此一來,url 變成:

https://www.example.com/blog?page=10&started_at=12345678
https://www.example.com/blog?page=11&started_at=12345690
https://www.example.com/blog?page=12&started_at=12345710

started_at 變成 unix timestamp,而資料庫對時間欄位 index。如此一來,資料庫在查詢的時候就可以先 B+tree 找到 started_at 的節點 (或是小於他最近的節點),然後連續抽出一百筆。

另外一種則是在產品面上「妥協」,也就是方法保持不變,但限制「一個 thread 最多只能回 1000 篇」,這在 2ch 或是論壇上很常看到。

Datomic 以及 RethinkDB...

Baron Schwartz (Percona 的 Chief Performance Architect) 寫了一篇「Immutability, MVCC, and garbage collection」狂酸 DatomicRethinkDB (喔,還稍微提到 CouchDB)。

裡面提到了 append-only B-tree 這的資料結構,優點以及會遇到的問題。(而這些問題都是致命的...)

下面的 comment 就看到 Datomic 的人跑出來反擊了,不過我懶的看了... XD

RDBMS 這麼多人發展這麼久了,不太有機會有萬靈丹突然出現解決一切問題... (這表示之前的人都是笨蛋?)

新出來一個 RDBMS 系統,官網做的很漂亮,是由一個商業公司拿錢發展出來,號稱可以解決很多問題,大概都可以先跳過去... XD