MySQL分表

随着大数据时代的来临,越来越大的数据量冲击着我们的系统,很多脆弱的系统在数据洪水的猛攻下早已不堪重负甚至垮掉。随着计算机硬件的飞速发展,千兆、万兆网卡,光纤,SSD硬盘,DDR4等等最新硬件的出现,计算机的硬件性能不再是我们系统优化的重要关注点,慢慢的我们发现现在的Web系统绝大多数性能的瓶颈都来自数据库。

前置系统即使你提供再多的web应用服务器,买再好的负载均衡设备,接最快的骨干线路却仍被数据库底下的性能所“坑爹”,页面动不动就卡死,查询一条数据要很久....

所以优化我们的数据库是最省钱也是最有效的方法,可以使我们的系统性能大幅度的提升,优化数据库的方法有很多,例如:采用SSD固态硬盘存储核心数据,增加数据库集群等等。下面我们要介绍的一种就是“分表”优化,这种优化相对简单,在数据库设计时期就可做到合理的规划。

分表优化简单的来讲就是将“大表”拆分成“小表”,这里的“大”有两个维度的意思:

表字段水平维度:表字段多,一个表甚至有几十个字段。

表内容垂直维度:表数据量大,几百万,几千万甚至上亿条数据。

所以分表优化会从两个方向同时进行,垂直和水平。

一般来说我们执行一条SQL语句是按以下顺序进行的:

1.客户端将SQL通过连接发送的数据库服务器。

2.数据库服务器对SQL语句进行解析并做一系列处理。

3.执行SQL语句。

4.将执行结果返回给客户端。

期间诸如updae,delete等操作会造成一定程度上的“锁”,根据引擎不同,隔离级别设置不同可能会出现“锁字段”,“锁行”,“锁表”甚至“锁据库”等等情况。

这样带来的后果就是SQL执行时间长,查询队列中等待的SQL无法继续进行,从而造成系统操作时间大幅度增加等不良后果。

应对“锁”我们就需要合理的分表了。

下面我们就先来研究“垂直分表”:

据说MySQL可以支持1000个字段,然而往往我们是用不了也不建议用这么多的,一般情况下建议字段总数不要超过30个,10-20个比较合理,再多的话在关联查询时会造成效率上的浪费。当然这也不是绝对的,可以根据项目及具体情况来执行。

以下是一张用户表,仅作为举例使用,不必去考虑其具体设计及内容合理性:


        以下是建表SQL语句:

Sql代码  

  1. CREATE TABLE `USER` (
  2. `USR_ID` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘用户编号‘,
  3. `NAME` varchar(20) DEFAULT NULL COMMENT ‘姓名‘,
  4. `LOGIN_NAME` varchar(64) NOT NULL COMMENT ‘登录名‘,
  5. `PASSWD` varchar(64) NOT NULL COMMENT ‘密码‘,
  6. `CUSTORM_ID` int(11) DEFAULT NULL COMMENT ‘客户代码‘,
  7. `STATUS` int(11) DEFAULT NULL COMMENT ‘用户状态‘,
  8. `SAFE_QUESTION` int(11) DEFAULT NULL COMMENT ‘安全提示问题‘,
  9. `SAFE_ANSWER` varchar(32) DEFAULT NULL COMMENT ‘安全提示答案‘,
  10. `CREATE_DATE` datetime DEFAULT NULL COMMENT ‘创建日期‘,
  11. `ACTIV_CODE` varchar(32) DEFAULT NULL COMMENT ‘激活码‘,
  12. `USR_TYPE` int(11) DEFAULT NULL COMMENT ‘用户类型‘,
  13. `MOBILE` int(15) DEFAULT NULL COMMENT ‘手机‘,
  14. `QQ` int(15) DEFAULT NULL COMMENT ‘QQ‘,
  15. `ADDRESS` int(150) DEFAULT NULL COMMENT ‘联系地址‘,
  16. `AGE` int(10) DEFAULT NULL COMMENT ‘年龄‘,
  17. PRIMARY KEY (`USR_ID`)
  18. );

这个表内容信息丰富可以很全面的查询出所有的用户信息,既然如此我们还有必要利用分表去优化它吗?答案是肯定的,有必要!

在访问量不大的情况下把所有信息都放置到一张表中可以很容易的获取所有信息,给我们代码的开发带来了极大的便利,但是一旦用户量激增,这种表结构就会产生很严重的诟病,例如:登录和更新用户信息同时进行,很容易导致锁表,相互影响;又如修改密码和修改其他信息也会如此等等。为了应对未来这种高并发的情况我们就应该合理的去设计库表了。

首先,我们可以将用户安全相关信息提取出来,如:密码,登录名,安全提示问题,安全提示答案。将这些信息组成一个名为“PASSWD”的表,这样做的好处是:将登录及相关安全信息独立出来以供功能单一如“登录”的业务调用,这样就可以减轻一部分表的压力,登录时只到“PASSWD”查询即可完成操作,当有必要时再去查询其他信息,这样做也有另一个好处,就是可以将PASSWD的查看及修改权限固定,仅限一定的mysql用户可以操作以提升安全性。

其次,我们将用户的相关联系信息提取,如:姓名,联系地址,年龄,手机,QQ。这些信息组成一个名为“USER_INFO”的表,这样我们就可以很方便的去扩展此表的字段及信息,更利于日后的更新及维护。

最后,剩下的字段组成新的“USER”表,此表只负责存储与用户业务相关的字段,使得“USER”表能更好的贴近相关业务,这三张表通过字段“USR_ID”进行关联。

分完后的表如下:


        建表SQL语句:

Sql代码  

  1. CREATE TABLE `USER` (
  2. `USR_ID` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘用户编号‘,
  3. `CUSTORM_ID` int(11) DEFAULT NULL COMMENT ‘客户代码‘,
  4. `STATUS` int(11) DEFAULT NULL COMMENT ‘用户状态‘,
  5. `CREATE_DATE` datetime DEFAULT NULL COMMENT ‘创建日期‘,
  6. `ACTIV_CODE` varchar(32) DEFAULT NULL COMMENT ‘激活码‘,
  7. `USR_TYPE` int(11) DEFAULT NULL COMMENT ‘用户类型‘,
  8. PRIMARY KEY (`USR_ID`)
  9. );
  10. CREATE TABLE `PASSWD` (
  11. `USR_ID` int(11) NOT NULL COMMENT ‘用户编号‘,
  12. `LOGIN_NAME` varchar(64) NOT NULL COMMENT ‘登录名‘,
  13. `PASSWD` varchar(64) NOT NULL COMMENT ‘密码‘,
  14. `SAFE_QUESTION` int(11) DEFAULT NULL COMMENT ‘安全提示问题‘,
  15. `SAFE_ANSWER` varchar(32) DEFAULT NULL COMMENT ‘安全提示答案‘
  16. );
  17. CREATE TABLE `USER_INFO` (
  18. `USR_ID` int(11) NOT NULL COMMENT ‘用户编号‘,
  19. `NAME` varchar(20) DEFAULT NULL COMMENT ‘姓名‘,
  20. `ADDRESS` int(150) DEFAULT NULL COMMENT ‘联系地址‘,
  21. `AGE` int(10) DEFAULT NULL COMMENT ‘年龄‘,
  22. `MOBILE` int(15) DEFAULT NULL COMMENT ‘手机‘,
  23. `QQ` int(15) DEFAULT NULL COMMENT ‘QQ‘
  24. );

当然以上分表并不是绝对的,可以根据具体情况去考虑分配方法及实现,我在这里只是提供一个思路,不必去严格要求上述分法的合理性,仁者见仁智者见智。

总结:垂直分表适合字段较多且业务关联较多的情况,将这些字段分散到不同业务相关的表中分别维护,这样不同的业务之间不会相互影响或制约。

另一种分表方式就是“水平分表”:

垂直分表应用于字段,水平分表就应用于表内容了。

我们知道一旦表内容非常多的时候查询起来就会很慢,虽然建立索引可以减少查询时间,但这毕竟不是根本解决办法。虽然MySQL没有硬性限制单表的大小,但是任何人都知道“表容量是不能无限制的增长的,这样影响性能”。

我们可以在SQL控制台输入命令“SHOW TABLE STATUS”来查看表的大小及状态。


        水平分表的思路其实就是将一个内容高负荷的表拆分成一些小表以提高性能,如:论坛表结构。

众所周知一个论坛对应了很多子论坛,子论坛又对应了很多帖子,帖子又对应了很多回复,结构如:

论坛 < 子论坛 forum < 帖子 topic < 回复 reply

我们就可以forum按论坛id进行区分,如:forum_001,forum_002,forum_003....

查询时我们利用特定算法拼接表名来进行操作。

当然这是一种比较极端的做法,这种做法局限性也很强,一旦表结构修改将产生令人恐怖的修改工作量,水平分表类似于“分区分表”,我们会在接下来学习分区分表相关内容。

水平分表优先需要解决“主键”问题,当全部数据集中在同一张表中时,我们可以利用MySQL的内部机制auto_increment 很轻易的实现主键自增,但是水平分表后每一张表都各种维护一份主键生成策略,这样就会产生重复冲突的现象,所以我们分表之前首先需要解决主键的生成问题。

以下是几种解决方案:

1.设置主键起始值

加入我们已经将表水平分成了3张表,TABLE1,TABLE2,TABLE3,每张表容纳10万份数据,那么TABLE1 的主键范围就应该是1-10万,而TABLE2 主键范围则为10万1-20万,TABLE3 主键范围则为20万1-30万,依次类推。

我们在创建表的时候可以手动的指定每张表主键增长的起始值,如TABLE1 起始值为1,TABLE2 为100001,TABLE3 为200001...

建表语句则为:

Sql代码  

  1. CREATE TABLE `TABLE1` (
  2. ...
  3. ) AUTO_INCREMENT=1
  4. CREATE TABLE `TABLE2` (
  5. ...
  6. ) AUTO_INCREMENT=100001
  7. CREATE TABLE `TABLE3` (
  8. ...
  9. ) AUTO_INCREMENT=200001

在建表时人为指定主键起始值的做法简单明了,维护成本小,不必额外关注主键生成问题。 但是在建表时直接声明起始值的做法有些生硬,我们可以将建表语句与主键设置语句分离,这样维护起来更加方便灵活:

Java代码  

  1. CREATE TABLE `TABLE1` (
  2. ...
  3. )
  4. alter table `TABLE1` AUTO_INCREMENT=1
  5. CREATE TABLE `TABLE2` (
  6. ...
  7. )
  8. alter table `TABLE2` AUTO_INCREMENT=100001
  9. CREATE TABLE `TABLE3` (
  10. ...
  11. )
  12. alter table `TABLE3` AUTO_INCREMENT=200001

sql语句的大概意思应该明白了吧,里面的错误就不必较真了。

2.利用拼接方式

这种方式下我们不必为每张表维护不同的主键ID,每张表完全可以都是从1-10万相同即可,在使用表数据时需要程序中人为加入另一个标识符,如表名:

Java代码

  1. 主键:TABLE1_1001 代表TABLE1中的1001数据
  2. 主键:TABLE2_1001 代表TABLE2中的1001数据

这样做的好处就是建表时全部采用相同的条件语句,不必单独维护主键异同,使用时需要在程序中动态的去判断该数据所属的表即可。

如主键ID显示可以变成1_1001,2_1001等等,将表和数据的ID分离。

3.利用外部实现

也就是在程序或一张单独的表中维护主键的值,在每次插入时取一下主键值。

时间: 2024-11-05 22:51:42

MySQL分表的相关文章

mysql分表方法-----MRG_MyISAM引擎分表法

一般来说,当我们的数据库的数据超过了100w记录的时候就应该考虑分表或者分区了,这次我来详细说说分表的一些方法.目前我所知道的方法都是MYISAM的,INNODB如何做分表并且保留事务和外键,我还不是很了解. 首先,我们需要想好到底分多少个表,前提当然是满足应用.这里我使用了一个比较简单的分表方法,就是根据自增id的尾数来分,也就是说分0-9一共10个表,其取值也很好做,就是对10进行取模.另外,还可以根据某一字段的md5值取其中几位进行分表,这样的话,可以分的表就很多了. 好了,先来创建表吧,

mysql 分表与分区

一.操作环境 数据达到百w甚于更多的时候,我们的mysql查询将会变得比较慢, 如果再加上连表查询,程序可能会卡死.即使你设置了索引并在查询中使用到了索引,查询还是会慢.这时候你就要考虑怎么样来提高查询速度了. 抛弃其他的不讲,只从mysql本身的优化来讲,我所知道的方法有三种:mysql集群,mysql分表,mysql分区 二.mysql集群 mysql集群成本比较高,不过这不是这里讲的重点,后期开一篇文章,专门来讲这方面的知识. 三.mysql分表 1. 当数据达到百w,千w的时候,我们就想

mysql分表和表分区详解

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

MYSQL 分表原理(转)

简介:引用MySQL官方文档中的一段话:MERGE存储引擎,也被认识为MRG_MyISAM引擎,是一个相同的可以被当作一个来用的MyISAM表的集合."相同"意味着所有表同样的列和索引信息.你不能合并列被以不同顺序列于其中的表,没有恰好同样列的表,或有不同顺序索引的表.而且,任何或者所有的表可以用myisampack来压缩.例子:mysql> show engines;+--------------------+---------+------------------------

mysql分表的三种方法

mysql分表的3种方法 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. 根据个人经验,mysql执行一个sql的过程如下:1,接收到sql;2,把sql放到排队队列中 ;3,执行sql;4,返回执行结果.在这个执行过程中最花时间在什么地方呢?第一,是排队等待的时间,第二,sql的执行时间.其实这二个是一回事,等待的同时,肯定有sql在执行.所以我们要缩短sql的执行

mysql分表研究

分表是分散数据库压力的好方法. 分表,最直白的意思,就是将一个表结构分为多个表,然后,可以再同一个库里,也可以放到不同的库. 当然,首先要知道什么情况下,才需要分表.个人觉得 单表记录条数达到百万到千万级别时就要使用分表了. 1,分表的分类 1>纵向分表 将本来可以在同一个表的内容,人为划分为多个表.(所谓的本来,是指按照关系型数据库的第三范式要求,是应该在同一个表的.) 分表理由:根据数据的活跃度进行分离,(因为不同活跃的数据,处理方式是不同的) 案例: 对于一个博客系统,文章标题,作者,分类

使用Merge存储引擎实现MySQL分表

一.使用场景 Merge表有点类似于视图.使用Merge存储引擎实现MySQL分表,这种方法比较适合那些没有事先考虑分表,随着数据的增多,已经出现了数据查询慢的情况. 这个时候如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码.所以使用Merge存储引擎实现MySQL分表可以避免改代码. Merge引擎下每一张表只有一个MRG文件.MRG里面存放着分表的关系,以及插入数据的方式.它就像是一个外壳,或者是连接池,数据存放在分表里面. 对于增删改查,直接操作总表即可. 二.建表 1.用户1表

mysql分表场景分析与简单分表操作

为什么要分表 首先要知道什么情况下,才需要分表个人觉得单表记录条数达到百万到千万级别时就要使用分表了,分表的目的就在于此,减小数据库的负担,缩短查询时间. 表分割有两种方式: 1水平分割:根据一列或多列数据的值把数据行放到两个独立的表中. 水平分割通常在下面的情况下使用: 表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度. 表中的数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用. 需要把数据存

一、mysql分表简单介绍

一.Mysql分表的原因 1.当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了. 分表的目的就在于此,减小数据库的负担,缩短查询时间. 2.mysql中有一种机制是表锁定和行锁定,为什么要出现这种机制,是为了保证数据的完整性, 我举个例子来说吧,如果有二个sql都要修改同一张表的同一条数据,这个时候怎么办呢,是不是二个sql都可以同时修改这条数据呢? 很显然mysql对这种情况的处理是,一种是表锁定(myisam存储引擎),一个是行锁定(innod

mysql分表规则(转)

author:skatetime:2013/05/14 Mysql分表准则 在大量使用mysql时,数据量大.高访问时,为了提高性能需要分表处理,简介下mysql分表的标准,后续会继续补充 环境:业务类型:OLTP硬件:cpu:8cpu 2.4GHZmem:48G磁盘:raid5 6×sas 什么样的表需要拆分:根据表的体积.表的行数.访问特点来衡量表是否需要拆分 一.拆分标准是:  1.表的体积大于2G或行数大于1000w,以单表主键等简单形式访问数据,这个时候需要分表  2.表的体积大于2G