php实现mysql分表

一、场景说明

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 条数据。

代码示例:

<?php

function 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中,循环插入之后,未分表之前的数据就都复制到了对应的数据表中。

当然,这只是其中的一种方式,还有其他方式。有自己想法的朋友可以在下方留言互相讨论。

猜你喜欢

转载自blog.csdn.net/m_nanle_xiaobudiu/article/details/81096344