一、场景说明
1、为什么要进行分表
随着数据量的不断增大,一张表中的数据肯定也会越来越多,甚至达到百万甚至千万级。我们通常会通过搭建mysql集群(主从同步),读写分离来实现优化数据库查询执行效率。
但是由于数据表本身是具有表锁(myisam)以及行锁(innodb)的。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作。这样就导致如果我们对一张表进行增删改操作时,mysql就会进行表锁或者行锁,导致其他的sql排队时间增长。
为了减轻表锁和行锁带来的其他sql执行时间延长的问题,我们就需要对数据表进行分表。如果对数据表进行分表操作,把一张表分成10张表,那肯定会减少其他sql的排队时间,进而提高sql的执行效率。
注:主从同步:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/81086243
二、开始分表
一张数据表中有uid 0000001 到 uid = 50000000 条数据。
代码示例:
<?phpfunction getUserInfoTable($uid)
{$i = $uid % 10;$table = sprintf("user_info_%s", $i);$check_sql = "SELECT COUNT(1) exist from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test' AND table_name ='{$table}' ";$result = $this->link->fetchOne($check_sql);$sql = <<<EOD
CREATE TABLE IF NOT EXISTS `{$table}` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`uid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',`comic_id` int(10) unsigned NOT NULL DEFAULT '0',`chapter_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '章节ID',`t` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '时间',`read_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '阅读状态 1已阅读 2未阅读',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
EOD;if ($result['exist'] == 0) {$this->link->execute($sql);}return $table;
}
注:如果已经有一些数据了,这时理论上也是可以采用上面这种方式进行分表的。
比如已经有20万条数据,这时我才开始意识到这张表需要进行分表了,这时候怎么办呢?我们可以这样,for循环uid,并对uid进行取模,或者是直接用uid的范围进行划分,根据一定算法(比如上面就是对uid进行取模)查出此uid应该在哪张分表后的数据表中,比如uid = 1000085,取模之后就要在user_info_5 这张数据表中。那我们就将查询出的uid = 1000085的用户信息插入到新数据表user_info_5中,循环插入之后,未分表之前的数据就都复制到了对应的数据表中。
当然,这只是其中的一种方式,还有其他方式。有自己想法的朋友可以在下方留言互相讨论。