以下的是分表的策略:
对于con_mms_file_info,con_mms_info和con_video_file_code_info这三张表以mid路由,这样同一个mid的数据都在一张表里好管理维护,而且按照sql的执行率来看以这三张表以mid操作的
频率是比较高的,其他查询需要在程序端进行合并。
首先想到的是以下两种方式:
散列方式mid:
优点:分散热点增删改查
缺点:后期再扩容迁移麻烦,以前10张表,要是10张表也不够,变成20张表,那以前的所有数据按照散列算法都不能命中,需要重新分配。
按mid增长步长:
优点:扩容简单。
缺点:热点数据都集中在一张表里,因为热点的都是近期的数据。
最后确定策略
最佳方式:
mid增长步长+mid散列
先划分组表名con_mms_sharding_group,如表con_mms_file_info,结构如下:
id table_group min_id max_id writable table_name
0 0 0 26489180 false con_mms_file_info
1 1 26489180 60000000 false con_mms_file_info
2 2 60000000 6000000000(尽量无限最大) true con_mms_file_info
说明:
table_group:组标识,和table_name拼表前缀
min_id 和max_id:mid的区间范围
writable:标识这个组里的表是否可插入数据,但是修改和删除不限制
table_name:要分表的table名称
这个结构存到数据库,并做业务端缓存,这样李刚等外围业务也可以取,来进行sql路由,每个组下面划分表,可以以规定就是10张表,也可以在这个结构里添加个字段table_count写明这个组有几张表。
路由步骤:
前期按照tablegroup为一组,每个组里面包含各个散列的table,0_0~0_9,如表为con_mms_file_info_0_0到表con_mms_file_info_0_9为一组tablegroup,分10张表。
以mid来当增长标识,先配置最小mid和最大mid,如group0的最小为0,最大为26489180,则以mms_file_info表为例,这个组mid数为26489180个,而如果每个mid对应平均
5个媒资文件,那数量是26489180*5,如果分为10张表,那每张表是26489180*5/10个。这个表里的数量都可以根据这个来调。所以当有个mid为27489181这个大于26489180而在
group1的空间里所以就会路由con_mms_file_info_1的组里再去以取模10确定真正的表名。
路由策略:根据mid判断增长区域是在哪个tablegroup里 就拼哪个tablegroup的表前缀,如con_mms_file_info_0为group0组,再根据表的数量10取模路由到到哪个表,如第8个表
那表名为con_mms_file_info_0_8即为最后的表名。这样既最大化的分散了热点数据,也保证了扩容方便。
对于insert操作,先去全局id表里取增长id为这个数据的id,然后去分组表里取writable为true的可写组,再拼组前缀并根据mid去路由并插入表中。
最后的组无限大是为,所有mid都能落入表里,如果最后的组里的表数据量大时再施行分表。
对于sql条件里带mid的sql,如果不带需要自行拼装查询,所有表查询然后组装,或者先查出mid再路由查询。目前分析了下myibatis里的配置sql应该都能拼装查询并组装取到数据。
就是实现上麻烦点没有以前简单。
全局id生成方案:
利用来自Flicker的解决方案:
auto_increment + replace into + MyISAM
创建表:
CREATE TABLE Tickets64 (
id bigint(20) unsigned NOT NULL auto_increment,
stub char(1) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY stub (stub)
) ENGINE=MyISAM
每个需要分配的表都需要单独建立一个这样的sequence表。
该方案中Sequence表使用的是MyISAM引擎,以获取更高的性能,
MyISAM引擎使用的是表级别的锁,MyISAM对表的读写是串行的,因此不必担心在并发时两次读取会得到同一个ID。
使用时用下面这个操作进行,在一个事务会话里提交:
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
最好用纯jdbc来实现效率高,用myibatise也可以实现。
使用REPLACE INTO插入数据,主要是希望利用mysql自身的机制生成ID
SELECT LAST_INSERT_ID()必须要于REPLACE INTO语句在同一个数据库连接下才能得到刚刚插入的新ID,否则返回的值总是0。