今天工作遇到需要处理大数据模块,游客数据表,结构大概是这样的:
create table if not exists tourist(
phone varchar(30) not null, #游客手机
name varchar(30) not null, #游客名称
place varchar(45), #籍贯
id_card varchar(36), #身份证
primary key(phone));
因为后期游客数据会达到10亿的量级,单个数据表肯定是不可行,根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉。水平分表能够很大程度较少这些压力。
按照每张表存放1000w条记录,需要分100个表。而且分表后,我还能通过游客手机号码,准确判定到他数据落在哪张表上。
常见分表方式
1.按时间分表
这种分表方式有一定的局限性,当数据有较强的实效性,如微博发送记录、微信消息记录等,这种数据很少有用户会查询几个月前的数据,如就可以按月分表。
2.按区间范围分表
一般在有严格的自增id需求上,如按照user_id水平分表:
table_1 user_id从1~100w
table_2 user_id从101~200w
table_3 user_id从201~300w
...
3.hash分表
通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。
我这边选用的是hash取模分表:
create table if not exists tourist_(tblid)(
id bigint not null, #sprintf("%u", crc32($phone))
phone varchar(30) not null, #游客手机
name varchar(30) not null, #游客名称
place varchar(45), #籍贯
id_card varchar(36), #身份证
primary key(id));
//预先创建100个表,根据手机号码判定数据落到哪张表
function get_tblid($phone, $tblnum = 100) {
//计算字符串的32位CRC(循环冗余校验), 该函数可用于验证数据完整性
//为了确保从 crc32() 函数中获得正确的字符串表示,您需要使用 printf() 或 sprintf() 函数的 %u 格式符。
//如果未使用 %u 格式符,结果可能会显示为不正确的数字或者负数。
$crc = sprintf("%u", crc32($phone));
//对结果进行取余数
$tblid = intval(fmod($crc, $tblnum));
//保证数据区域在[1, $tblnum]之间
return ($tblid+1);
}