MySQL 水平拆分之后,自動增長的ID有什么好的解決辦法?
問題描述
當(dāng)單表的數(shù)據(jù)量過大時,會采用MySQL進行水平拆分,請問原先的自動增長的ID有什么好的解決辦法?
問題解答
回答1:水平拆分后,同一張表的數(shù)據(jù)放在不同的庫上,無法再依賴數(shù)據(jù)庫本身的auto_increment實現(xiàn)ID的唯一性,多個庫之間產(chǎn)生的ID會造成沖突。因此ID不應(yīng)該由數(shù)據(jù)庫來分配,那么應(yīng)該由什么來分配,我覺得要分兩種情況:
如果應(yīng)用是通過數(shù)據(jù)庫中間件來訪問后臺的MySQL,那么ID應(yīng)該由中間件來生成
如果沒有中間件,ID由應(yīng)用生成
但無論是應(yīng)用還是中間件,應(yīng)用肯定會是多個的(多個客戶端),而中間件,中間件一般也不會部署一個單實例,這樣會有單點問題(single point of failure), 中間件在生產(chǎn)環(huán)境下,是集群部署的。
那么問題就清晰明了得多了,無論是上面哪一種情況,實際上你需要的是一個全局的,global的ID生成器。
全局的global生成器有很多種方式可以實現(xiàn)
從公共數(shù)據(jù)庫取ID
把ID生成策略放在zookeeper集群上,去zookeeper集群上取全局ID
基本的策略就是這樣了。還有一點小細節(jié)。
全局ID最好以表來劃分,一個表對應(yīng)一個全局ID上下文,不同的表去不同的全局ID上下文取。
另外一個,無論是中間件也好,應(yīng)用也好,取全局ID時不要每次只取一個,那樣性能太低了,更好的方式是每次取一段ID,比如應(yīng)用1取到了1-50這段ID,那么它就可以在這50個ID用完之前,不再需要去取ID;應(yīng)用2也去取ID,那么它會取到51-100這段ID,這個思想有點像儲存食物過冬一樣。
回答2:目前我這已知的方法:1.修改原有的自增列,變?yōu)椴蛔栽鲋麈I。自己維護主鍵
2.水平拆分為拆分已有數(shù)據(jù),也就是說拆分出去的表的數(shù)據(jù)不會再做變化。新增的數(shù)據(jù)依然自增。(注意不能設(shè)置自增填充空白id)
3.做個統(tǒng)一算法。自增id需要計算后寫入,而不是自動維護
回答3:我這邊之前也有這樣的需求。我是這么處理的:把主鍵列去掉自增長,通過redis的incr產(chǎn)生自增序列值,插入的時候指定id的值
回答4:1.把自增ID這個功能,用一張表與一個存儲過程做成一個小模塊。
2.被拆分的表,當(dāng)有數(shù)據(jù)INSERT時,就調(diào)用這個存儲過程來申請一個新ID。
回答5:分表后主鍵要自己生成最好,很多開源的主鍵生成策略算法,比如說twitter的snowflake等如果不想改動程序的話,設(shè)置每個集群中自增 ID 起始點(auto_increment_offset)以及 ID 自增步長(auto_increment_increment),讓目前每個集群的起始點錯開,達到將 ID 相對分段的效果來滿足全局唯一的效果。優(yōu)點是實現(xiàn)簡單,對應(yīng)用透明,缺點就是,以后如果根據(jù)id做路由的話不好擴展
