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。)