MySQL实战45讲
林晓斌
网名丁奇,前阿里资深技术专家
立即订阅
43178 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 这一次,让我们一起来搞懂MySQL
免费
基础篇 (8讲)
01 | 基础架构:一条SQL查询语句是如何执行的?
02 | 日志系统:一条SQL更新语句是如何执行的?
03 | 事务隔离:为什么你改了我还看不见?
04 | 深入浅出索引(上)
05 | 深入浅出索引(下)
06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
07 | 行锁功过:怎么减少行锁对性能的影响?
08 | 事务到底是隔离的还是不隔离的?
实践篇 (37讲)
09 | 普通索引和唯一索引,应该怎么选择?
10 | MySQL为什么有时候会选错索引?
11 | 怎么给字符串字段加索引?
12 | 为什么我的MySQL会“抖”一下?
13 | 为什么表数据删掉一半,表文件大小不变?
14 | count(*)这么慢,我该怎么办?
15 | 答疑文章(一):日志和索引相关问题
16 | “order by”是怎么工作的?
17 | 如何正确地显示随机消息?
18 | 为什么这些SQL语句逻辑相同,性能却差异巨大?
19 | 为什么我只查一行的语句,也执行这么慢?
20 | 幻读是什么,幻读有什么问题?
21 | 为什么我只改一行的语句,锁这么多?
22 | MySQL有哪些“饮鸩止渴”提高性能的方法?
23 | MySQL是怎么保证数据不丢的?
24 | MySQL是怎么保证主备一致的?
25 | MySQL是怎么保证高可用的?
26 | 备库为什么会延迟好几个小时?
27 | 主库出问题了,从库怎么办?
28 | 读写分离有哪些坑?
29 | 如何判断一个数据库是不是出问题了?
30 | 答疑文章(二):用动态的观点看加锁
31 | 误删数据后除了跑路,还能怎么办?
32 | 为什么还有kill不掉的语句?
33 | 我查这么多数据,会不会把数据库内存打爆?
34 | 到底可不可以使用join?
35 | join语句怎么优化?
36 | 为什么临时表可以重名?
37 | 什么时候会使用内部临时表?
38 | 都说InnoDB好,那还要不要使用Memory引擎?
39 | 自增主键为什么不是连续的?
40 | insert语句的锁为什么这么多?
41 | 怎么最快地复制一张表?
42 | grant之后要跟着flush privileges吗?
43 | 要不要使用分区表?
44 | 答疑文章(三):说一说这些好问题
45 | 自增id用完怎么办?
特别放送 (1讲)
直播回顾 | 林晓斌:我的 MySQL 心路历程
结束语 (1讲)
结束语 | 点线网面,一起构建MySQL知识网络
MySQL实战45讲
登录|注册

43 | 要不要使用分区表?

林晓斌 2019-02-20
我经常被问到这样一个问题:分区表有什么问题,为什么公司规范不让使用分区表呢?今天,我们就来聊聊分区表的使用行为,然后再一起回答这个问题。

分区表是什么?

为了说明分区表的组织形式,我先创建一个表 t:
CREATE TABLE `t` (
`ftime` datetime NOT NULL,
`c` int(11) DEFAULT NULL,
KEY (`ftime`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
PARTITION BY RANGE (YEAR(ftime))
(PARTITION p_2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
PARTITION p_2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
PARTITION p_2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
PARTITION p_others VALUES LESS THAN MAXVALUE ENGINE = InnoDB);
insert into t values('2017-4-1',1),('2018-4-1',1);
图 1 表 t 的磁盘文件
我在表 t 中初始化插入了两行记录,按照定义的分区规则,这两行记录分别落在 p_2018 和 p_2019 这两个分区上。
可以看到,这个表包含了一个.frm 文件和 4 个.ibd 文件,每个分区对应一个.ibd 文件。也就是说:
对于引擎层来说,这是 4 个表;
对于 Server 层来说,这是 1 个表。
你可能会觉得这两句都是废话。其实不然,这两句话非常重要,可以帮我们理解分区表的执行逻辑。

分区表的引擎层行为

我先给你举个在分区表加间隙锁的例子,目的是说明对于 InnoDB 来说,这是 4 个表。
图 2 分区表间隙锁示例
这里顺便复习一下,我在第 21 篇文章和你介绍的间隙锁加锁规则。
我们初始化表 t 的时候,只插入了两行数据, ftime 的值分别是,‘2017-4-1’ 和’2018-4-1’ 。session A 的 select 语句对索引 ftime 上这两个记录之间的间隙加了锁。如果是一个普通表的话,那么 T1 时刻,在表 t 的 ftime 索引上,间隙和加锁状态应该是图 3 这样的。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《MySQL实战45讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(26)

  • 夹心面包 置顶
    我说下我的感想
    1 经典的利用分区表的场景
        1 zabbix历史数据表的改造,利用存储过程创建和改造
        2 后台数据的分析汇总,比如日志数据,便于清理
    这两种场景我们都在执行,我们对于分区表在业务采用的是hash 用户ID方式,不过大规模应用分区表的公司我还没遇到过
    2 分区表需要注意的几点
    总结下
    1 由于分区表都很大,DDL耗时是非常严重的,必须考虑这个问题
    2 分区表不能建立太多的分区,我曾被分享一个因为分区表分区过多导致的主从延迟问题
    3 分区表的规则和分区需要预先设置好,否则后来进行修改也很麻烦

    作者回复: 👍 非常好

    2019-02-20
    12
  • aliang
    老师,mysql还有一个参数是innodb_open_files,资料上说作用是限制Innodb能打开的表的数量。它和open_files_limit之间有什么关系吗?

    作者回复: 好问题。

    在InnoDB引擎打开文件超过 innodb_open_files这个值的时候,就会关掉一些之前打开的文件。

    其实我们文章中 ,InnoDB分区表使用了本地分区策略以后,即使分区个数大于open_files_limit ,打开InnoDB分区表也不会报“打开文件过多”这个错误,就是innodb_open_files这个参数发挥的作用。

    2019-02-21
    12
  • 老师确认下,5.7.9之后的innodb分区表,是访问第一个表时不会去打开所有的分区表了吗?

    作者回复: 第一次访问的时候,要打开所有分区的

    2019-02-25
    6
  • 万勇
    老师,请问add column after column_name跟add column不指定位置,这两种性能上有区别吗?我们在add column 指定after column_name的情况很多。

    作者回复: 仅仅看性能,是没什么差别的

    但是建议尽量不要加after column_name,
    也就是说尽量加到最后一列。

    因为其实没差别,但是加在最后有以下两个好处:
    1. 开始有一些分支支持快速加列,就是说如果你加在最后一列,是瞬间就能完成,而加了after column_name,就用不上这些优化(以后潜在的好处)

    2. 我们在前面的文章有提到过,如果怕对线上业务造成影响,有时候是通过“先做备库、切换、再做备库”这种方式来执行ddl的,那么使用after column_name的时候用不上这种方式。

    实际上列的数据是不应该有影响的,还是要形成好习惯😆

    2019-02-21
    1
    5
  • 权恒星
    这个只适合单机吧?集群没法即使用innodb引擎,又支持分区表吧,只能使用中间件了。之前调研了一下,官方只有ndb cluster才支持分区表?

    作者回复: 对这篇文章讲的是单机上的单表多分区

    2019-02-20
    4
  • godtrue
    1:啥是分区表?
    创建表的时候,使用了数据分区相关的语法,存储数据的时候,存储引擎会根据分区规则将不同的数据存入不同的分区文件。
    2:使用分区表的劣势?
    2-1:MySQL 在第一次打开分区表的时候,需要访问所有的分区——打开的表较多,性能糟糕也可能报打开的表超过设置的问题。
    2-2:在 server 层,认为这是同一张表,因此所有分区共用同一个 MDL 锁——锁粒度大,影响并发度,站在Server看也是合理的,不过站在存储引擎的角度看就不合理了。
    2-3:在引擎层,认为这是不同的表,因此 MDL 锁之后的执行过程,会根据分区表规则,只访问必要的分区——被访问到的分区。
    3:使用分区表的优势?
    分区表的一个显而易见的优势是对业务透明,相对于用户分表来说,使用分区表的业务代码更简洁。还有,分区表可以很方便的清理历史数据。
    4:啥时候适合使用分区表?
    单表过大时,使用时注意一下两点
    4-1:分区并不是越细越好。实际上,单表或者单分区的数据一千万行,只要没有特别大的索引,对于现在的硬件能力来说都已经是小表了。
    4-2:分区也不要提前预留太多,在使用之前预先创建即可。比如,如果是按月分区,每年年底时再把下一年度的 12 个新分区创建上即可。对于没有数据的历史分区,要及时的 drop 掉。
    5:使用分区表,有其特点的根本原因?
    对于Server层,分区表还是一个表
    对于存储引擎层,分区表会是多张表
    2019-08-09
    3
  • 怀刚
    请教下采用”先做备库、切换、再做备库”DDL方式不支持AFTER COLUMN是因为BINLOG原因吗?
    以上DDL方式会存在影响“有损”的吧?“无损”有哪些方案呢?如果备库承载读请求但又不能接受“长时间”延时

    作者回复: 1. 对,binlog对原因
    2. 如果延迟算损失,确实是有损的。备库上的读流量要先切换到主库(也就是为什么需要在低峰期做做个操作)

    2019-03-09
    2
  • daka
    本期提到了ndb,了解了下,这个存储引擎高可用及读写可扩展性功能都是自带,感觉是不错,为什么很少见人使用呢?生产不可靠?
    2019-02-21
    2
  • One day
    这次竟然只需要再读两次就能读懂,之前接触过mycat和sharding-jdbc实现分区,老师能否谈谈这方面的呢

    作者回复: 赞两次 😆

    这个就是我们文章说的“分库分表中间件”
    不过看到不少公司都会要在这基础上做点定制化

    2019-02-20
    2
  • 郭江伟
    此时主键包含自增列+分区键,原因为对innodb来说分区等于单独的表,自增字段每个分区可以插入相同的值,如果主键只有自增列无法完全保证唯一性。
    测试表如下:
    mysql> show create table t\G
           Table: t
    Create Table: CREATE TABLE `t` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `ftime` datetime NOT NULL,
      `c` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`,`ftime`),
      KEY `ftime` (`ftime`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    /*!50100 PARTITION BY RANGE (YEAR(ftime))
    (PARTITION p_2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
     PARTITION p_2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
     PARTITION p_2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
     PARTITION p_others VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
    1 row in set (0.00 sec)
    mysql> insert into t values(1,'2017-4-1',1),(1,'2018-4-1',1);
    Query OK, 2 rows affected (0.02 sec)
    mysql> select * from t;
    +----+---------------------+------+
    | id | ftime | c |
    +----+---------------------+------+
    | 1 | 2017-04-01 00:00:00 | 1 |
    | 1 | 2018-04-01 00:00:00 | 1 |
    +----+---------------------+------+
    2 rows in set (0.00 sec)

    mysql> insert into t values(null,'2017-5-1',1),(null,'2018-5-1',1);
    Query OK, 2 rows affected (0.02 sec)

    mysql> select * from t;
    +----+---------------------+------+
    | id | ftime | c |
    +----+---------------------+------+
    | 1 | 2017-04-01 00:00:00 | 1 |
    | 2 | 2017-05-01 00:00:00 | 1 |
    | 1 | 2018-04-01 00:00:00 | 1 |
    | 3 | 2018-05-01 00:00:00 | 1 |
    +----+---------------------+------+
    4 rows in set (0.00 sec)

    作者回复: 👍

    2019-02-20
    2
  • wljs

    老师我想问个问题 我们公司一个订单表有110个字段 想拆分成两个表 第一个表放经常查的字段 第二个表放不常查的 现在程序端不想改sql,数据库端来实现 当查询字段中 第一个表不存在 就去关联第二个表查出数据 db能实现不

    作者回复: 用view可能可以实现部分你的需求,但是强烈不建议这么做。
    业务不想修改,就好好跟他们说,毕竟这样分(常查和不常查的垂直拆分)是合理的,对读写性能都有明显的提升的。

    2019-02-20
    2
  • 于欣磊
    阿里云的DRDS就是分库分表的中间件典型代表。自己实现了一个层Server访问层在这一层进行分库分表(对透明),然后MySQL只是相当于存储层。一些Join、负载Order by/Group by都在DRDS中间件这层完成,简单的逻辑插叙计算完对应的分库分表后下推给MySQL https://www.aliyun.com/product/drds
    2019-02-25
    1
  • NICK
    老师,如果用户分区,业务要做分页过滤查询怎么做才好?

    作者回复: 分区表的用法跟普通表,在sql语句上是相同的。

    2019-02-25
    1
  • 锋芒
    老师,请问什么情况会出现间隙锁?能否专题讲一下锁呢?

    作者回复: 20、21两篇看下

    2019-02-23
    1
  • helloworld.xs
    请教个问题,一般mysql会有查询缓存,但是update操作也有缓存机制吗?使用mysql console第一次执行一个update SQL耗时明显比后面执行相同update SQL要慢,这是为什么?

    作者回复: update的话,主要应该第一次执行的时候,数据都读入到了

    2019-02-21
    1
  • Q
    老师 请问下 网站开发数据库表是myisam和innodb混合引擎 考虑管理比较麻烦 想统一成innodb 请问是否影响数据库或带来什么隐患吗? 网站是网上商城购物类型的

    作者回复: 应该统一成innodb
    网上商城购物类型更要用InnoDB,因为MyISAM并不是crash-safe的。

    测试环境改完回归下

    2019-02-20
    1
  • undifined
    老师,有两个问题
    1. 图三的间隙锁,根据“索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁”,不应该是 (-∞,2017-4-1],(2017-4-1,2018-4-1)吗,图4左边的也应该是 (-∞,2017-4-1],(2017-4-1, supernum),是不是图画错了
    2. 现有的一个表,一千万行的数据, InnoDB 引擎,如果以月份分区,即使有 MDL 锁和初次访问时会查询所有分区,但是综合来看,分区表的查询性能还是要比不分区好,这样理解对吗

    思考题的答案
    ALTER TABLE t
      ADD COLUMN (id INT AUTO_INCREMENT ),
      ADD PRIMARY KEY (id, ftime);

    麻烦老师解答一下,谢谢老师

    作者回复: 1. 我们语句里面是 where ftime='2017-5-1' 哈,不是“4-1”
    2. “分区表的查询性能还是要比不分区好,这样理解对吗”,其实还是要看表的索引情况。
       当然一定存在一个数量级N,把这N行分到10个分区表,比把这N行放到一个大表里面,效率高

    2019-02-20
    1
  • 千木
    老师您好,你在文章里面有说通用分区规则会打开所有引擎文件导致不可用,而本地分区规则应该是只打开单个引擎文件,那你不建议创建太多分区的原因是什么呢?如果是本地分区规则,照例说是不会影响的吧,叨扰了

    作者回复: “本地分区规则应该是只打开单个引擎文件”,并不是哈,我在文章末尾说了,也会打开所有文件的,只是说本地分区规则有优化,比如如果文件数过多,就会淘汰之前打开的文件句柄(暂时关掉)。

    所以分区太多,还是会有影响的

    2019-02-20
    1
  • 长期规划
    老师,分区后,事务以及jion语句需要修改吗
    2019-11-25
  • 加载中……
    老师好,请教个问题,文章中说“单表或者单分区的数据一千万行,只要没有特别大的索引,对于现在的硬件能力来说都已经是小表了”。其中的"现在的硬件能力"在这句话的场景下大概指的是个什么样的具体配置?
    2019-08-28
收起评论
26
返回
顶部