mysql分表,分区的区别和联系

MySQL分表分区详解
本文详细介绍了MySQL分表和分区的概念、实现方式及其优缺点,包括分表的三种方法和分区的两种方式,并探讨了两者之间的区别与联系。
部署运行你感兴趣的模型镜像
一,什么是mysql分表,分区

什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法

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的方法来获得表名:


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

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

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

3.利用merge存储引擎来实现分表

我觉得这种方法比较适合,那些没有事先考虑,而已经出现了得,数据查询慢的情况。这个时候如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码,因为程序里面的sql语句已经写好了,现在一张表要分成几十张表,甚至上百张表,这样sql语句是不是要重写呢?举个例子,我很喜欢举子

mysql>show engines;的时候你会发现mrg_myisam其实就是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=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  
Query OK, 0 rows affected (0.05 sec)  

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=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  
Query OK, 0 rows affected (0.01 sec)  

mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('张映', 0);  
Query OK, 1 row affected (0.00 sec)  

mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);  
Query OK, 1 row affected (0.00 sec)  

mysql> CREATE TABLE IF NOT EXISTS `alluser` (  
->   `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 ;  
Query OK, 0 rows affected, 1 warning (0.00 sec)  

mysql> select id,name,sex from alluser;  
+----+--------+-----+  
| id | name   | sex |  
+----+--------+-----+  
|  1 | 张映 |   0 |  
|  1 | tank   |   1 |  
+----+--------+-----+  
2 rows in set (0.00 sec)  

mysql> INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0);  
Query OK, 1 row affected (0.00 sec)  

mysql> select id,name,sex from user2  
-> ;  
+----+-------+-----+  
| id | name  | sex |  
+----+-------+-----+  
|  1 | tank  |   1 |  
|  2 | tank2 |   0 |  
+----+-------+-----+  
2 rows in set (0.00 sec)  

从上面的操作中,我不知道你有没有发现点什么?假如我有一张用户表user,有50W条数据,现在要拆成二张表user1和user2,每张表25W条数据,

INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id <= 250000

INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id > 250000

这样我就成功的将一张user表,分成了二个表,这个时候有一个问题,代码中的sql语句怎么办,以前是一张表,现在变成二张表了,代码改动很大,这样给程序员带来了很大的工作量,有没有好的办法解决这一点呢?办法是把以前的user表备份一下,然后删除掉,上面的操作中我建立了一个alluser表,只把这个alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的

a,如果你使用 alter table 来把 merge 表变为其它表类型,到底层表的映射就被丢失了。取而代之的,来自底层 myisam 表的行被复制到已更换的表中,该表随后被指定新类型。

b,网上看到一些说replace不起作用,我试了一下可以起作用的。晕一个先

mysql> UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2;  
Query OK, 1 row affected (0.00 sec)  
Rows matched: 1  Changed: 1  Warnings: 0  

mysql> select * from alluser;  
+----+--------+-----+  
| id | name   | sex |  
+----+--------+-----+  
|  1 | 张映 |   0 |  
|  1 | tank   |   1 |  
|  2 | tank2  |   1 |  
+----+--------+-----+  
3 rows in set (0.00 sec)  

c,一个 merge 表不能在整个表上维持 unique 约束。当你执行一个 insert,数据进入第一个或者最后一个 myisam 表(取决于 insert_method 选项的值)。mysql 确保唯一键值在那个 myisam 表里保持唯一,但不是跨集合里所有的表。

d,当你创建一个 merge 表之时,没有检查去确保底层表的存在以及有相同的机构。当 merge 表被使用之时,mysql 检查每个被映射的表的记录长度是否相等,但这并不十分可靠。如果你从不相似的 myisam 表创建一个 merge 表,你非常有可能撞见奇怪的问题。

优点:扩展性好,并且程序代码改动的不是很大

缺点:这种方法的效果比第二种要差一点

什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上,具体请参考mysql分区功能详细介绍,以及实例。
mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的。如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样呢,我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,这个时候,我们可以把数据分配到不同的磁盘里面去。
分区的二种方式

1.横向分区

什么是横向分区呢?就是横着来分区了,举例来说明一下,假如有100W条数据,分成十份,前10W条数据放到第一个分区,第二个10W条数据放到第二个分区,依此类推。也就是把表分成了十分,根用merge来分表,有点像哦。取出一条数据的时候,这条数据包含了表结构中的所有字段,也就是说横向分区,并没有改变表的结构。

2.纵向分区

什么是纵向分区呢?就是竖来分区了,举例来说明,在设计用户表的时候,开始的时候没有考虑好,而把个人的所有信息都放到了一张表里面去,这样这个表里面就会有比较大的字段,如个人简介,而这些简介呢,也许不会有好多人去看,所以等到有人要看的时候,在去查找,分表的时候,可以把这样的大字段,分开来。

感觉数据库的分区好像是切苹果,到底是横着切呢,还是竖着切,根据个人喜好了,mysql提供的分区属于第一种,横向分区,并且细分成很多种方式。

分区优点

1,分区可以分在多个磁盘,存储更大一点

2,根据查找条件,也就是where后面的条件,查找只查找相应的分区不用全部查找了

3,进行大数据搜索时可以进行并行处理。

4,跨多个磁盘来分散数据查询,来获得更大的查询吞吐量

二.mysql分表和分区有什么区别呢
1.实现方式上

a),mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件,一个.MYD数据文件,.MYI索引文件,.frm表结构文件。

[root@BlackGhost test]# cat alluser.MRG |more  
user1  
user2  
#INSERT_METHOD=LAST  

从上面我们可以看出,alluser.MRG里面就存了一些分表的关系,以及插入数据的方式。可以把总表理解成一个外壳,或者是联接池。

b),分区不一样,一张大表进行分区后,他还是一张表,不会变成二张表,但是他存放数据的区块变多了。

[root@BlackGhost test]# ls |grep aa  
aa#P#p1.MYD  
aa#P#p1.MYI  
aa#P#p3.MYD  
aa#P#p3.MYI  
aa.frm  
aa.par  

从上面我们可以看出,aa这张表,分为二个区,p1和p3,本来是三个区,被我删了一个区。我们都知道一张表对应三个文件.MYD,.MYI,.frm。分区呢根据一定的规则把数据文件和索引文件进行了分割,还多出了一个.par文件,打开.par文件后你可以看出他记录了,这张表的分区信息,根分表中的.MRG有点像。分区后,还是一张,而不是多张表。

2.数据处理上

a),分表后,数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。看下面的例子:

select * from alluser where id='12'表面上看,是对表alluser进行操作的,其实不是的。是对alluser里面的分表进行了操作。

b),分区呢,不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表呢,还是一张表。数据处理还是由自己来完成。

3.提高性能上

a),分表后,单表的并发能力提高了,磁盘I/O性能也提高了。并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出现高并发的话,总表可以根据不同的查询,将并发压力分到不同的小表里面。磁盘I/O性能怎么搞高了呢,本来一个非常大的.MYD文件现在也分摊到各个小表的.MYD中去了。

b),mysql提出了分区的概念,我觉得就想突破磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。
在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。

4.实现的难易度上

a),分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式根分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。

b),分区实现是比较简单的,建立分区表,根建平常的表没什么区别,并且对开代码端来说是透明的。


三.mysql分表和分区有什么联系呢

1,都能提高mysql的性高,在高并发状态下都有一个良好的表面。

2,分表和分区不矛盾,可以相互配合的,对于那些大访问量,并且表数据比较多的表,我们可以采取分表和分区结合的方式(如果merge这种分表方式,不能和分区配合的话,可以用其他的分表试),访问量不大,但是表数据很多的表,我们可以采取分区的方式等。

转载请注明 作者:海底苍鹰
地址:http://blog.51yip.com/mysql/1029.html


您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think> 嗯,用户想了解MySQL分区分表区别。这个问题挺实用的,因为很多人在处理大数据量时都会面临这个选择。用户可能是个后端工程师或者DBA,正在为系统设计数据存储方案。 从引用内容看,用户提供的资料已经比较全面了,但需要我来整理得更清晰些。分区分表确实容易混淆,核心区别在于:分区是逻辑划分物理存储,而分表是物理拆分成多个表。 分区表的特点很鲜明,它像是个大柜子里的隔层,数据还在一个表里,但存储被分割了。这样用户查询时还能用原来的表名,数据库会自动定位分区。不过分区数量上限是个硬伤,最多1024个分区可能不够某些超大系统使用。 分表就彻底多了,直接把大表拆成多个小表,每张表都是独立的。这样扩展性无敌,但代价就是查询变复杂。用户得自己处理数据路由,跨表查询也得手动UNION。引用里提到的MERGE存储引擎是个折中方案,可惜不能分区同时用。 用户可能还关心性能对比。分区在查询优化上确实有优势,特别是范围查询时可以直接跳过无关分区。而分表在写入高并发场景更出色,毕竟压力被分散到不同物理表了。 突然想到个重要区别没在引用里强调:事务支持。分区表因为还在一个数据库实例里,能保证ACID;但分表如果跨了数据库实例,分布式事务就是大难题了。这点得在回答里补充。 运维方面也是重点。分区表用常规的OPTIMIZE TABLE就行,分表却要逐个表维护。用户要是怕麻烦,分区显然省心得多。 最后考虑给用户些实用建议。中等数据量用分区足够,要是数据真的海量或者要跨服务器,再考虑分表。其实现在很多企业用分库分表中间件了,下次可以建议用户了解下MyCat或者ShardingSphere。 </think>以下是MySQL分区表与分表的详细对比,结合核心区别、实现方式适用场景: --- ### **一、核心区别** | **维度** | **分区表(Partitioning)** | **分表(Sharding)** | |----------------|---------------------------------------------------|-----------------------------------------------| | **物理存储** | 单表物理存储拆分为多个文件(如.ibd),**仍为逻辑上的单表** | **拆分为多个独立的物理表**(如`table_001`, `table_002`) | | **数据管理** | 由**MySQL内部自动管理**分区路由 | **需应用层或中间件**(如ShardingSphere)手动路由 | | **SQL兼容性** | 应用**无需修改SQL**,透明访问原表名 | 需**显式指定表名**或通过中间件改写SQL | | **事务支持** | 单分区事务(ACID) | 跨表事务需分布式事务(如XA) | --- ### **二、实现方式对比** #### **1. 分区表示例(按范围分区)** ```sql -- 创建分区表(按年份分区) CREATE TABLE sales ( id INT, sale_date DATE, amount DECIMAL(10,2) ) PARTITION BY RANGE(YEAR(sale_date)) ( PARTITION p2018 VALUES LESS THAN (2019), PARTITION p2019 VALUES LESS THAN (2020), PARTITION p2020 VALUES LESS THAN MAXVALUE ); -- 查询时自动路由到分区(无需修改SQL) SELECT * FROM sales WHERE sale_date BETWEEN '2019-01-01' AND '2019-12-31'; -- 仅扫描p2019分区 ``` #### **2. 分表示例(水平分表)** ```sql -- 手动创建分表 CREATE TABLE sales_2019 (id INT, sale_date DATE, amount DECIMAL(10,2)); CREATE TABLE sales_2020 (id INT, sale_date DATE, amount DECIMAL(10,2)); -- 应用层需按年份路由查询 -- Java伪代码示例: String tableName = "sales_" + year; executeQuery("SELECT * FROM " + tableName + " WHERE ..."); ``` --- ### **三、性能与扩展性对比** | **场景** | **分区表** | **分表** | |------------------|-----------------------------------------------|-----------------------------------------------| | **大数据量** | 单表上限**约1024个分区**,数据量受单机限制 | **支持水平扩展**,数据可分到不同服务器 | | **查询性能** | 范围查询快(分区裁剪) | 高并发下更优(压力分散) | | **写入性能** | 单点写入瓶颈 | 支持多节点并行写入 | | **维护复杂度** | 低(ALTER TABLE管理分区) | 高(需中间件+数据迁移工具) | --- ### **四、适用场景** #### **分区表适合:** 1. **中等数据量优化**(单机可承载) > 如:日志表按月份归档,历史数据快速删除(直接`DROP PARTITION`)[^3] 2. **范围查询频繁** > 如:时间范围、数值区间查询(分区裁剪减少扫描量)[^1] 3. **简化管理** > 无需修改业务SQL,DDL操作便捷(如`REORGANIZE PARTITION`)[^4] #### **分表适合:** 1. **超大规模数据**(TB级以上) > 如:电商订单表,分表后部署到多台服务器[^2] 2. **高并发写入** > 如:物联网设备数据采集,分散写入压力[^4] 3. **需要线性扩展** > 如:用户表按ID哈希分表,随业务增长动态扩容[^1] --- ### **五、混合使用建议** - **分区+分表组合**: 超大规模场景可先分表(如按用户ID分库分表),再对单个分表进行分区(如按时间分区)[^3] > 例如: > `user_orders_001` 表再按 `order_date` 分区,兼顾扩展性与查询效率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值