PARTITION 分区技术介绍就在这里不细述了,有心人请自行百度。
遇到问题
我这里遇到的情况是,一个平台,下边有许多许多的代理商,每个代理商对应一个 site_id.
因为每个代理商之间的数据都是互不影响的,想根据 HASH(site_id) 来分区。
数据量因为不是很大,而且写比读频繁,所以暂时只考虑 MYISAM 引擎。
CREATE TABLE `test` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`site_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '站点id',
PRIMARY KEY (`id`),
KEY `siteIndex` (`site_id`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8 PARTITION BY HASH (site_id) PARTITIONS 10;
于是遇到
错误码: 1503
A PRIMARY KEY must include all columns in the table's partitioning function
这个问题的原因是因为 分区的参数必须包含 PRIMARY KEY , 主键id, 必须放在HASH(id)中。
所以,在创建表的时候不能设置主键。因此 id 字段也不能自增。
解决方案
将id 改成 char(16),创建使用唯一 guid的方案:
/**
* get guid by
*
* @return string|void
*/
function guid($pre = '') {
return ($pre ? $pre : '') . substr(md5(uniqid(($pre ? $pre : '') . mt_rand(), true)), 9, 16);
}
因为 id 必须要为数字(需要coreseek配合全文索引),所以这个方案暂时放一放。
后来,还是决定把 id 字段 INT(10) 不变,变为索引字段。
然后外建一个表:
CREATE TABLE `maxid` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`tb` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '表名',
`maxid` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '最大自增id',
`step` INT(5) UNSIGNED NOT NULL DEFAULT '1' COMMENT '步长',
PRIMARY KEY (`id`),
UNIQUE KEY `tb` (`tb`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;
手工统计自增的id。
(在高并发的系统中,需要在获取 maxid 之前要加锁。否则极有可能会产生重复的id。)