前一篇文章談到 mysql innodb 處理 clustered index 的機制,所以就來談一下 mysql partition 機制。
由於 innodb 會優先使用 primary key 作為 clustered index 來劃分表格的儲存階層,無法避免的,製作 partition 時,就得將 partition key 加入到 primary key 內,這個時候選擇 primary key 以及 partition key 就變得相當重要,甚至可捨去 primary key 。
在處理不同情境的資料,如:時間序列性質的資料。需使用時間條件 range condition 來查詢。
而在 partition 上使用 range condition 做查詢時,就會牽扯到 partition pruning 。
所謂的 partition pruning 就是,mysql 會在查詢資料之前,將 query 的條件做剖析,將需要做索引查詢的 partition 過濾,縮小搜尋範圍,這個時候用到的是 partition key。
雖然 mysql 可以 concurrently 在不同 partition 查詢,並合併結果,但如果 partition key 設計得不好,就會變成所有的 partition 都得掃過一次。
想知道 SQL Query 可以如何做 partition pruning 可以使用 explain partition [Query] 。 (MySQL 5.7 已經把 explain partition 預設啟用,因此不需再輸入 partition keyword。)
不過,就算把 partition key 設計得很好,還是有陷阱。
這個陷阱就是,你在 table 上所下的索引如果和 primary key 沒有交集,不是 unique index,mysql 還是得在所有的 partition 中掃過一次 index。
如果你一定要在 table 下使用 non-unique index 必須記得 partition 的數量必須要壓在 16 以下才不至於影響效能太多。
依照開啟不同的 Thread 數量,對 non-unique index lookup over partition 都會造成不小的衝擊,普遍來說只要 partition 數量超過 124 後就會使得 non-unique index lookup 相當緩慢。
也因此 partition 並不是銀彈,不是什麼場景全部套上 partition 就一定得以解救,有的時候得到的效能更差。
另外一個 partition 所帶來的限制,就是 FK (Foreign Key) 無法在 partition table 上使用,到底該不該 drop foreign key? 這點也造成了相當的爭論,可謂斷尾求生。
通常,一個好的 partition 規劃只有很少的索引,甚至是沒有索引的。 是的,你沒聽錯,在某些查詢條件下,只使用 partition 就算是用 full table scan 都會比不做 partition 只用 index 還快,尤其是特別大的 table。
後記:在捷運上用手機注音 key 完整篇文章,隔壁的 OL 盯著我的手機看,還拿 instagram 出來拍照是怎麼回事。