Mysql常见水平分表方案

根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉;水平分表能够很大程度较少这些压力。

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算法计算出数据存储表的表名,然后访问相应的表。

按如下分10张表:

functionget_hash_table($table,$userid)

{

$str=crc32($userid);

if($str<0){

$hash="0".substr(abs($str),0,1);

}else{

$hash=substr($str,0,2);

}

return$table."_".$hash;

}

echo get_hash_table('message','user18991');//结果为message_10

echo get_hash_table('message','user34523');//结果为message_13

另外,介绍我现在就是采用简单的取模分表:

/**

* @param string $table_name 表名

* @param int $user_id 用户id

* @param int $total 分表总数

* @link http://www.phpddt.com

*/

functionhash_table($table_name,$user_id,$total)

{

return$table_name.'_'.(($user_id%$total)+1);

}

echo hash_table("artice",1234,5);//artice_5

echo hash_table("artice",3243,5);//artice_4

4.利用merge存储引擎分表

感觉merge存储引擎类似sql中union的感觉,但是查询效率不高。

如下举例,拥有1000w记录的old_user表分表:

(1)创建new_user表使用merge存储引擎

mysql>CREATE TABLE IF NOT EXISTS`user1`(

->`id`int(11)NOT NULL AUTO_INCREMENT,

->`name`varchar(50)DEFAULT NULL,

->`sex`int(1)NOT NULL DEFAULT'0',

->PRIMARY KEY(`id`)

->)ENGINE=MyISAMDEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

QueryOK,0rows affected(0.05sec)

mysql>CREATE TABLE IF NOT EXISTS`user2`(

->`id`int(11)NOT NULL AUTO_INCREMENT,

->`name`varchar(50)DEFAULT NULL,

->`sex`int(1)NOT NULL DEFAULT'0',

->PRIMARY KEY(`id`)

->)ENGINE=MyISAMDEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

QueryOK,0rows affected(0.01sec)

mysql>INSERT INTO`user1`(`name`,`sex`)VALUES('张映',0);

QueryOK,1row affected(0.00sec)

mysql>INSERT INTO`user2`(`name`,`sex`)VALUES('tank',1);

QueryOK,1row affected(0.00sec)

mysql>CREATE TABLE IF NOT EXISTS`new_user`(

->`id`int(11)NOT NULL AUTO_INCREMENT,

->`name`varchar(50)DEFAULT NULL,

->`sex`int(1)NOT NULL DEFAULT'0',

->INDEX(id)

->)TYPE=MERGE UNION=(user1,user2)INSERT_METHOD=LAST AUTO_INCREMENT=1;

QueryOK,0rows affected,1warning(0.00sec)

mysql>selectid,name,sexfromnew_user;

+----+--------+-----+

|id|name|sex|

+----+--------+-----+

|1|张映|0|

|1|tank|1|

+----+--------+-----+

2rowsinset(0.00sec)

mysql>INSERT INTO`new_user`(`name`,`sex`)VALUES('tank2',0);

QueryOK,1row affected(0.00sec)

mysql>selectid,name,sexfromuser2

->;

+----+-------+-----+

|id|name|sex|

+----+-------+-----+

|1|tank|1|

|2|tank2|0|

+----+-------+-----+

2rowsinset(0.00sec)

(2)我old_user数据进行分表:

INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT(user.id,user.name,user.sex)FROM old_userwhereuser.id<=5000000

INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT(user.id,user.name,user.sex)FROM old_userwhereuser.id>10000000

1,做mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等

有人会问mysql集群,根分表有什么关系吗?虽然它不是实际意义上的分表,但是它启到了分表的作用,做集群的意义是什么呢?为一个数据库减轻负担,说白了就是减少sql排队队列中的sql的数量,举个例子:有10个sql请求,如果放在一个数据库服务器的排队队列中,他要等很长时间,如果把这10个sql请求,分配到5个数据库服务器的排队队列中,一个数据库服务器的队列中只有2个,这样等待时间是不是大大的缩短了呢?这已经很明显了。所以我把它列到了分表的范围以内,我做过一些mysql的集群:

linux mysql proxy 的安装,配置,以及读写分离

mysql replication 互为主从的安装及配置,以及数据同步

优点:扩展性好,没有多个分表后的复杂操作(php代码)

缺点:单个表的数据量还是没有变,一次操作所花的时间还是那么多,硬件开销大。

2,预先估计会出现大数据量并且访问频繁的表,将其分为若干个表

这种预估大差不差的,论坛里面发表帖子的表,时间长了这张表肯定很大,几十万,几百万都有可能。

聊天室里面信息表,几十个人在一起一聊一个晚上,时间长了,这张表的数据肯定很大。像这样的情况很多。所以这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。以聊天信息表为例:

我事先建100个这样的表,message_00,message_01,message_02……….message_98,message_99.然后根据用户的ID来判断这个用户的聊天信息放到哪张表里面,你可以用hash的方式来获得,可以用求余的方式来获得,方法很多,各人想各人的吧。下面用hash的方法来获得表名:

复制代码代码如下:


function get_hash_table($table,$userid) {

$str = crc32($userid);

if($str<0){

$hash = "0".substr(abs($str), 0, 1);

}else{

$hash = substr($str, 0, 2);

}

return $table."_".$hash;

}

echo get_hash_table('message' , 'user18991');     //结果为message_10

echo get_hash_table('message' , 'user34523');    //结果为message_13

?>

说明一下,上面的这个方法,告诉我们user18991这个用户的消息都记录在message_10这张表里,user34523这个用户的消息都记录在message_13这张表里,读取的时候,只要从各自的表中读取就行了。

优点:避免一张表出现几百万条数据,缩短了一条sql的执行时间

缺点:当一种规则确定时,打破这条规则会很麻烦,上面的例子中我用的hash算法是crc32,如果我现在不想用这个算法了,改用md5后,会使同一个用户的消息被存储到不同的表中,这样数据乱套了。扩展性很差。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 一,先说一下为什么要分表当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在...
    MrKai平凡之路阅读 869评论 1 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • MySQL 数据库常用命令 1、MySQL常用命令 create database name; 创建数据库 use...
    55lover阅读 4,781评论 1 57
  • 有人太多在路口,拥堵我们的相遇。
    ringpor阅读 344评论 0 1
  • 我不想放下你 我想見你 我好想你
    天娜日記阅读 137评论 0 0