{eval=Array;=+count(Array);}

问答专栏Q & A COLUMN

MySQL分库分表之后,id主键如何处理?

stormgensstormgens 回答0 收藏1
收藏问题

9条回答

张宪坤

张宪坤

回答于2022-06-28 14:38

我从分库分表存在的问题和怎么做来回答一下这个问题。。

一,分库分表的ID主键不能依赖于数据库的自增,因为多库中会重复!

通常使用外接的数据组件获取全局唯一的ID:比如加强型UUID(根据Ip,时间戳等得到)和使用Redis(RedisAtomicLong)和zookeeper的API获取,Twitter的雪花算法等等!

二,分库分表之后的连接查询比较困难!

问题没法避免,通常拆分SQL,使用多次查询,用查到的结果再分别查别的结果!

三,分布式事务的数据一致性很难保证!

可以使用TCC编程模型保证两处的事务都能正确提交,但是这种方式对代码的侵入比较重!也可以使用基于消息的数据一致性保证!

四,多数据的排序,分组,统计会比较困难!

1,用多线程,对多个节点分别查询,然后汇总!

2,也可以提前冗余查询表,将所有的经常查询的重点数据提前统一到个库表里!

分库分表涉及到的知识点比较多,建议使用专门的分库分表组件!本人有mycat使用经验,如果您有相关问题,欢迎前来探讨!

评论0 赞同0
  •  加载中...
Cheriselalala

Cheriselalala

回答于2022-06-28 14:38

数据库在做了分库分表之后,关于ID主键,我认为需要考虑这几点:


生成算法

当我们的数据库是单台的时候,是不用太操心主键的生成,但是当数据库进行了分库分表之后,那么主键的生成就需要注意了,至少不能使用数据库内部的自增长序列了,通常要引入分布式唯一标识码的生成算法。

  • 利用数据库生成:先说最笨的方法,利用数据库的自增长序列生成,数据库内唯一,有人会说,刚说完不能用数据库的自增长序列,这么快就要被打脸了么?其实这个的意思是,先利用(额外)的一台数据库,通过其自增长序列得到主键,然后作为分库分表的主键;

  • 利用Redis/MongoDB/zookeeper生成:Redis的单线程的,利用incr和increby;MongoDB的ObjectId;ZK通过znode数据版本;都可以生成全局的唯一标识码;

  • UUID:生成唯一标识码最常用的算法之一;

  • Snowflake:Twitter开源,基于zk,41位时间戳(毫秒数)+10位机器的ID+12位毫秒内的流水号+1位符号位(永远是0);

  • UidGenerator:百度开源,基于snowflake算法;

  • Leaf:美团开源,能保证全局唯一性、高可用、趋势递增(不太安全,比如泄露公司订单数量)、单调递增等。


扩容会比较麻烦

分库分表通常的方案都用主键mod分表的数量,来把数据路由到某一个数据库分片上。例如分了10张表,那么就是ID%10,得到结果0-9,代表不同的表;但是当数据量进一步增多的时候,单库的数据量达到了一定的级别之后,那么就需要分更多的表,那么这时候有哪些处理方案呢?

  • 做数据迁移:最简单暴力,也是最麻烦的一个方案;因为当分表(分库)数量增多的时候,因为分片规则的变化,每个表的数据都要被重新分配到多个新的表;

  • 如果id是一个增长的全局序列,当前有十张表,那么分表的算法为:id%10,根据0-9路由到10个表中;当表扩到20张的时候,扩容那一刻取max_id,那么未来分库的算法也就变成了:

if(id<max_id){id%10} else {id%20};
  • 有些分表的算法本身就带时间戳,可以基于id中的时间戳来实现,比如Snowflake算法(见上文),这个算法是一个64位的Long值,前42位就是一个精确到毫秒的时间戳,那么我们的分库算法也就可以以某个时间点来判断:

if(id中的时间<增加分表那一刻的时间){id%10} else {id%20};

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

评论0 赞同0
  •  加载中...
未东兴

未东兴

回答于2022-06-28 14:38

数据量达到查询瓶颈的时候,需要做一些拆分或索引优化处理。

对于使用id主键来说,分库分表都要做一些特别的设计,有以下几个方案。

1、id区间提前规划好,每个库分配好整数区间,每个库中的每个表也要规划号,数字那么大,总有区间能够容纳下增长的数字。

2、id采用32位全局uuid保证唯一

3、通过雪花算法,得到分布式环境下全局唯一的id

4、采用纳秒级时间戳+随机数+重试机制保证数据唯一。

由于数据库的索引大部分采用B+数数据结构来存储,主键的线性递增对数据的插入(B+树的拆分和合并)和查询性能有优势,所以建议采用能保证主键递增的方案。

评论0 赞同0
  •  加载中...
objc94

objc94

回答于2022-06-28 14:38

全局id生成算法 snowklake算法 用long型64位表示 1位表示符号位正整数 41位表示时间戳 10位表示机器码 12位表示顺序位

评论0 赞同0
  •  加载中...
U2FsdGVkX1x

U2FsdGVkX1x

回答于2022-06-28 14:38

为什么要分物理表呢? 分区的底层同样是物理分表但上层MySQL已做好一切展现给我们的是一个总表,不同的数据放到不同分区,CURD甚至索引完全就是当成一个表来操作,其实展现给用户的就是一张表,但底层分成了若干个区

评论0 赞同0
  •  加载中...
Cciradih

Cciradih

回答于2022-06-28 14:38

写个api,专门用来生成唯一id,用他来做主键

评论0 赞同0
  •  加载中...
kk_miles

kk_miles

回答于2022-06-28 14:38

苞米豆的mybatis-plus,只需要配置一下就可以,但我没有实际应用过

评论0 赞同0
  •  加载中...
canger

canger

回答于2022-06-28 14:38

id主键不用管。MySQL自己会处理。无非是操作的时候不一样

评论0 赞同0
  •  加载中...
Kyxy

Kyxy

回答于2022-06-28 14:38

看你怎么分,但无论怎么分都要保留或新建主建来关联数据,数据关联不起来,就废了。

评论0 赞同0
  •  加载中...

相关问题

最新活动

您已邀请0人回答 查看邀请

我的邀请列表

  • 擅长该话题
  • 回答过该话题
  • 我关注的人
向帮助了您的网友说句感谢的话吧!
付费偷看金额在0.1-10元之间
<