版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1433220
对[**数据库**](http://lib.csdn.net/base/mysql)表进行水平分割的时候,经常会遇到在不同的机器上生成全局唯一ID的问题。下面以[**MySQL**](http://lib.csdn.net/base/mysql)为例介绍对于在不同机器上生成全局唯一ID的几个解决途径,其思想也适用于其他数据库系统。
1. 使用auto_increment_increment和auto_increment_offset
假定有n个数据库,它们使用了auto\_increment字段来取得唯一ID,为了保证n个数据库同时具备全局唯一性,我们可以在每个数据库上分别指定初始值和步长,具体如下:
对于任一节点i(1<=i<=n)指定
auto_increment_increment=i
auto_increment_offset=n
如果以后系统扩展到m个数据库(m>n),则:
对于任一节点i(1<=i<=m)指定
auto_increment_increment=全局max(id)+i
auto_increment_offset=m
这种方法很简单,而且也不依赖于一个中心节点,因此是生成唯一ID的上佳选择。现有的服务器也很容易用这个方法来配置,特别是当你增加服务器或灾难恢复之后。
2. 在全局节点上创建一个表
在一个全局数据库节点上创建一个带有auto\_increment字段的表,应用就从这个表取得唯一性ID。
sql view plain copy
在这个语句执行后,可以使用MySQL的API:mysql\_insert\_id()来获得这个新生成的值。这个方法在不同语言中的实现都不太一样,以下是一个PERL的例子:
python view plain copy
用不着再使用另外的查询语句(比如select last\_insert\_id())来获取这个值。额外的查询又会在服务器之间多一次往返,这很没效率。如果使用这种全局分配器来产生唯一ID,要当心它会成为应用的瓶颈。
3. 使用memcache
在memcache API中有个incr()函数,它能产生一个唯一性ID供使用。虽然memcache很快(每秒钟几万个值),但它不是持续不断的。每次重启了memcache服务,都需要在缓存里初始化那个产生值。这就要求你初始化时,每次都要找出目前在各个数据分块使用的最大值,这个过程相当缓慢而且难以自动执行。
4. 批量分配编号
应用从全局节点上一次性地取得一批编号供自己使用,用完后,再申请一批。
5. 使用复合值
你可以使用一个复合值来做唯一性ID,比如一个数据库ID和自增长编号。可以使用单列主键值,并且使用整数的“高位”来保存数据库ID。简单的左移位(乘法)和加法可以完成这一目的。例如,使用无符号的bigint(64位)的高8位来保存数据库ID,那么就可以用下面的方式在数据库15上插入11:
insert into test(pk_col,...) values ((15<<56)+11,...);
这种方法的问题是需要额外的方式来产生键值,因为auto_increment不会帮助你做这件事。而且这种方法使主键值更大了,对InnoDB中的次主键有多重影响。
6. 使用双字段auto_increment键
这个只能在myisam表里使用:
sql view plain copy
7. 使用GUID
你可以使用UUID()函数来生成全局唯一的ID,GUID的值很大且不连续,因此它不适合做InnoDB表里的主键。MySQL中新的UUID\_SHORT函数能返回一个较短的连续的值,也更适于用作主键。