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

網(wǎng)公網(wǎng)安備