mysql分表详解

经常听到有人说“数据表太大了,需要分表”,“xxxx了,要分表”的言论,那么,到底为什么要分表?

难道数据量大就要分表?

mysql数据量对索引的影响

本人mysql版本为5.7

新增数据测试

为了测试mysql索引查询是否和数据量有关,本人做了以下的测试准备:

新建4个表article1,article2,article3,article4,article5 每个表分别插入20万,50万,100万,200万,1500万的数据,数据都是随机生成


1

2

3

4

5

6

7

8

9

10

11

12

13

14

    create table test.article1(

  id          int auto_increment comment ‘id‘

    primary key,

  user_id     int          not null comment ‘用户id‘,

  title       varchar(64)  not null comment ‘标题‘,

  add_time    datetime     null comment ‘新增时间‘,

  update_time int          null comment ‘更新时间‘,

  description varchar(255) null comment ‘简介‘,

  status      tinyint(1)   null comment ‘状态 1正常 0隐藏‘

)

  charset = utf8;

create index article_title_index

  on test.article1 (title);

生成数据脚本,使用easyswoole,多协程插入:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

<?php

include "./vendor/autoload.php";

\EasySwoole\EasySwoole\Core::getInstance()->initialize();

for ($i = 0; $i <= 2000; $i++) {//协程最多3000,创建1000个协程

    go(function () use ($i) {

        \App\Utility\Pool\MysqlPool::invoke(function (\App\Utility\Pool\MysqlPoolObject $mysqlObjectuse ($i) {

            for ($y = 0; $y <= 1000; $y++) {//每个协程插入100条数据

                $data = [

                    ‘user_id‘     => mt_rand(1, 2500),

                    ‘title‘       => \EasySwoole\Utility\Random::character(32),//随机生成32位字母的标题

                    ‘add_time‘    => date(‘Y-m-d H:i:s‘, mt_rand(strtotime(‘2018-01-01‘), strtotime(‘2019-01-01‘))),//随机生成日期

                    ‘update_time‘ => mt_rand(strtotime(‘2018-01-01‘), strtotime(‘2019-01-01‘)),//随机生成日期

                    ‘description‘ => getChar(mt_rand(8, 64)),//随机生成8-64位汉字,

                    ‘status‘      => mt_rand(0, 1),

                ];

                $mysqlObject->insert(‘article2‘$data);

            }

            echo "协程$i 插入完成\n";

        }, -1);

    });

}

function getChar($num)  // $num为生成汉字的数量

{

    $b ‘‘;

    for ($i = 0; $i $num$i++) {

        // 使用chr()函数拼接双字节汉字,前一个chr()为高位字节,后一个为低位字节

        $a chr(mt_rand(0xB0, 0xD0)) . chr(mt_rand(0xA1, 0xF0));

        // 转码

        $b .= iconv(‘GB2312‘‘UTF-8‘$a);

    }

    return $b;

}

生成的数据如图:

数据库总条数预览:


1

select (select count(1) from article1) as "1" , (select count(1) from article2) as "2", (select count(1) from article3) as "3", (select count(1) from article4) as "4", (select count(1) from article5) as "5";

查询时间测试

查询脚本


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

<?php

/**

 * Created by PhpStorm.

 * User: tioncico

 * Date: 19-5-11

 * Time: 下午7:20

 */

include "./vendor/autoload.php";

\EasySwoole\EasySwoole\Core::getInstance()->initialize();

go(function () {

    /**

     * @var $db \App\Utility\Pool\MysqlPoolObject

     */

    $db = \App\Utility\Pool\MysqlPool::defer();

    $startTime = microtimeFloat();

    //查询1000次

    for ($i = 0; $i < 10000; $i++) {

        $str =\EasySwoole\Utility\Random::character(32);//随机生成字符串,用于查询

        $data $db->where(‘title‘,$str)->getOne(‘article1‘);

    }

    echo "1耗时" . (microtimeFloat() - $startTime) . ‘秒‘.PHP_EOL;

    $startTime = microtimeFloat();

    //查询1000次

    for ($i = 0; $i < 10000; $i++) {

        $str =\EasySwoole\Utility\Random::character(32);//随机生成字符串,用于查询

        $data $db->where(‘title‘,$str)->getOne(‘article2‘);

    }

    echo "2耗时" . (microtimeFloat() - $startTime) . ‘秒‘.PHP_EOL;

    $startTime = microtimeFloat();

    //查询1000次

    for ($i = 0; $i < 10000; $i++) {

        $str =\EasySwoole\Utility\Random::character(32);//随机生成字符串,用于查询

        $data $db->where(‘title‘,$str)->getOne(‘article3‘);

    }

    echo "3耗时" . (microtimeFloat() - $startTime) . ‘秒‘.PHP_EOL;

    $startTime = microtimeFloat();

    //查询1000次

    for ($i = 0; $i < 10000; $i++) {

        $str =\EasySwoole\Utility\Random::character(32);//随机生成字符串,用于查询

        $data $db->where(‘title‘,$str)->getOne(‘article4‘);

    }

    echo "4耗时" . (microtimeFloat() - $startTime) . ‘秒‘.PHP_EOL;

    $startTime = microtimeFloat();

    //查询1000次

    for ($i = 0; $i < 10000; $i++) {

        $str =\EasySwoole\Utility\Random::character(32);//随机生成字符串,用于查询

        $data $db->where(‘title‘,$str)->getOne(‘article5‘);

    }

    echo "5耗时" . (microtimeFloat() - $startTime) . ‘秒‘.PHP_EOL;

});

function microtimeFloat()

{

    list($usec$sec) = explode(" ", microtime());

    return ((float)$usec + (float)$sec);

}

该脚本是一个实例脚本,在后面的其他测试中依旧使用该脚本,修改下字段和逻辑

title全索引查询一条时间情况:(为了准确,本人运行了多次)

可以看出,数据量在200万以下时,查询时间几乎没有差别,只是在数据量1400万时,查询1万次的时间增加了1秒

注:本人在之前测试,和之后测试时,查询article5时时间大概是2.1-2.5秒左右,可能mysql有其他知识点本人未掌握,所以没法详细解释

title全索引查询不限制条数时间情况:(为了准确,本人运行了多次)

可以看出,在200万数据之前 查询时间并没有太大的差距,1400万有一点点的差距

title like 左前缀 索引查询不限制条数时间情况:(为了准确,本人运行了多次)

根据这次测试,我们可以发现

1:mysql的查询和数据量的大小关系并不大(微乎其微)

2:mysql只要是命中索引,不管数据量有多大,都会非常快(快的一批,由于本人比较懒,并且本人之前也测试过单表1.5亿速度一样很快,就懒得继续新增2亿测试数据了,太累)

什么情况需要分表

从上面的章节可以发现,数据量的多少和查询速度其实关系不是很大,那么为什么要分表呢?原因有以下几种:

1:   单表 不涉及索引的操作太多,无法直接命中索引的

2:模糊查找范围过大,无法直接命中索引的,例如日志表查时间区间

3:单表数据量过大,操作繁忙的

4:数据量过大,有大部分数据很少访问的(冷热数据)
5:装逼,需要用分表装逼的

分表优缺点

在上面,我们已经知道了为什么要分表,分表该怎么分呢?

首先,我们需要先搞懂分表的意义

数据分表有着以下好处:

1:分散表压力,使其响应速度提高

2:数据降维,提升查询速度

3:分冷热数据,更好管理,备份

4:支持分布式部署数据库,将压力分担到其他服务器中

同时,缺点如下:

1:分表之后较难管理多表

2:join表时可能需要join多个

3:查询模糊数据时需要全部的表一起查

所以,数据量不大时候,不建议分表。

水平分表

根据数据的不同规则作为一个分表条件,区分数据以数据之间的分表叫做水平分表

水平分表是比较常见的分表方法,也是解决数据量大时候的分表方法,在水平分表中,也根据场景的不同而分表方法不同

取模分表

假设有个用户表(1000w用户)需要分表,那么我们可以根据该用户表的唯一标识(id ,用户账号)进行取模分表

重新新建n个表。例如5个, user1,user2,user3....uesr5

取出所有用户,根据 用户账号进行取模,例如:


1

2

3

4

5

6

<?php

$userAccount =‘tioncico‘;

$num =  (crc32($userAccount)%5);

$tableName ‘user‘.($num+1);

echo "{$userAccount}应该存储到{$tableName}表";

//tioncico应该存储到user3表

不建议使用id分表,因为一般情况下,我们是使用账号,或者其他唯一标识 来进行区分某个人的,如果你表设计像qq号一样,那完全可以将id命名为其他的字段,用于区分,自增id同样需要

取模分表法会使数据尽量的均衡分布,压力均衡,非常适合于需要通过特定标识字段查找数据的表(会员表)

冷热数据分表

冷热数据大多数体现在跟时间有关的 日志表,订单表上面

在冷热数据分表时,我们应该遵循以下几种分表规则

1:数据冷热分表,需要注意冷热数据的界限

例如,商城订单表,每天增加100万的订单,一年就会增加到3.6亿的订单数,而大多数情况下,用户只会查询近1-3个月的数据,我们可以

通过订单时间进行分表,只需要按照月份进行分表即可

2:通过取模分表,需要注意取模字段,

垂直分表

区分一条数据的不同字段,叫做垂直分表

垂直分表其实我们在设计数据库时,可能已经是用到了的,比如会员金额表,关联会员表的userId,这个时候,其实就可以叫做是垂直分表
把会员金额的字段分到了其他的表中(会员金额表)

垂直分表较为简单,有以下几种分法:

1:字段意义和表其他字段意义不同,可以尝试分表

2:字段占用空间太大,不常用或只在特定情况使用,可以尝试分表

3:字段与其他字段更新时间不同,可以尝试分表

原文地址:https://www.cnblogs.com/liliuguang/p/10935080.html

时间: 2024-08-29 03:53:31

mysql分表详解的相关文章

mysql 锁表详解

为了给高并发情况下的MySQL进行更好的优化,有必要了解一下mysql查询更新时的锁表机制. 一.概述 MySQL有三种锁的级别:页级.表级.行级. MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁:InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁. MySQL这3种锁的特性可大致归纳如下: 表级锁:开销小,

MySQL user表详解

Host: 10-4-13-72 User: Password: Select_priv: N Insert_priv: N Update_priv: N Delete_priv: N Create_priv: N Drop_priv: N Reload_priv: N 重新加载权限表 Shutdown_priv: N Process_priv: N 服务器管理 File_priv: N 加载服务器上的文件 Grant_priv: N References_priv: N Index_priv:

Mysql—用户表详解(mysql.user)

用户列(用户连接MySQL数据库需要输入的信息) Host User Password  %  domain_check  *55B565DA3839E5955A68EA96EB735  localhost  domain_check  *55B565DA3839E5955A68EA96EB735  127.0.0.1  domain_check  *55B565DA3839E5955A68EA96EB735  126.26.98.25  domain_check  *55B565DA3839E

mysql分表和表分区详解

为什么要分表和分区? 日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表.这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕.分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率. 什么是分表? 分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,每个表都对应三个文件,MYD数据文件,.MYI索引文件,.frm表结构文件.这些子表可以分布在

【mysql】mysql分表和表分区详解

为什么要分表和分区? 日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表.这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕.分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率. 什么是分表? 分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,每个表都对应三个文件,MYD数据文件,.MYI索引文件,.frm表结构文件.这些子表可以分布在

MySQL数据库优化详解(收藏)

MySQL数据库优化详解 mysql表复制 复制表结构+复制表数据mysql> create table t3 like t1;mysql> insert into t3 select * from t1;mysql索引 ALTER TABLE用来创建普通索引.UNIQUE索引或PRIMARY KEY索引ALTER TABLE table_name ADD INDEX index_name (column_list)ALTER TABLE table_name ADD UNIQUE (colu

MySQL主从架构详解

1.复制概述 Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves)上,并重新执行一遍来实现的.复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环.这些日志可以记录发送到从服务器的更新.当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置.从服务器接收

MySQL数据库备份详解

原文:MySQL数据库备份详解 对于任何数据库来说,备份都是非常重要的 数据库复制不能取代备份的作用 比如我们由于误操作,在主数据库上删除了一些数据,由于主从复制的时间很短,在发现时,从数据库上的数据可能也已经被删除了, 我们不能使用从数据库上的数据来恢复主数据库上的数据,只能通过备份进行误删除数据的恢复 一. 备份的分类 1.按备份的结果来分: 逻辑备份 其备份结果为SQL语句,适合于所有存储引擎,恢复时需要较多时间,逻辑备份时,对于MyISAM存储引擎是需要进行锁表操作的,通过使用的mysq

Mysql 三大特性详解

Mysql 三大特性详解 Mysql Innodb后台线程 工作方式 首先Mysql进程模型是单进程多线程的.所以我们通过ps查找mysqld进程是只有一个. 体系架构 InnoDB存储引擎的架构如下图所以,是由多个内存块组成的内存池,同时又多个后台线程进行工作,文件是存储磁盘上的数据. 后台线程 上面看到一共有四种后台线程,每种线程都在不停地做自己的工作,他们的分工如下: Master Thread: 是最核心的线程,主要负责将缓冲池中的数据异步刷新的磁盘,保证数据的一致性,包括脏页的刷新.合