大家好,我是 Snow Hide,作为《MySQL 实战》这个专栏的学员之一,这是我打卡的第 54 天,也是我第 116 次进行这种操作。
今天我温习了该专栏里一篇叫《为什么临时表可以重名?》的文章。
关键词总结:内存表和临时表的区别、临时表的特性(临时表在使用上的几个特点、临时表适合 join 优化场景的原因)、临时表的应用(两种比较常用的思路)、为什么临时表可以重用?(表中数据的存放方式在不同 MySQL 版本中的不同处理方式、MySQL 维护数据表时包含物理文件和内存里的表)、临时表和主备复制(MySQL 记录 binlog 时将主库执行语句的线程编号写到 binlog 中)。
所学总结:
内存表和临时表的区别
- 内存表,指的是使用 Memory 引擎的表,建表语法时 create table … engine=memory。这种表的数据都保存在内存里,系统重启的时候会被清空,但是表结构还在。除了这两个特性看上去比较 “奇怪” 外,从其他的特征上看,它就是一个正常的表;
- 而临时表,可以使用各种引擎类型。如果是使用 InnoDB 引擎或者 MyISAM 引擎的临时表,写数据的时候是写到磁盘上的。当然,临时表也可以使用 Memory 引擎。
临时表的特性
临时表在使用上的几个特点
- 建表语法是 create temporary table …;
- 一个临时表只能被创建它的 session 访问,对其他线程不可见。所以,图中 session A 创建的临时表 t,对于 session B 就是不可见的;
- 临时表可以与普通表同名;
- session A 内有同名的临时表和普通表的时候,show create 语句,以及增删改查语句访问的是临时表;
- show tables 命令不显示临时表。
临时表适合 join 优化场景的原因
- 不同 session 的临时表是可以重名的,如果有多个 session 同时执行 join 优化,不需要担心表名重复导致建表失败的问题;
- 不需要担心数据删除问题。如果使用普通表,在流程执行过程中客户端发生了异常断开,或者数据库发生异常重启,还需要专门来清理中间过程中生成的数据表。而临时表由于会自动回收,所以不需要这个额外的操作。
临时表的应用
两种比较常用的思路
- 第一种思路,在 proxy 层的进程代码中实现排序。
这种方式的优势是处理速度快,拿到分库的数据以后,直接在内存中参与计算。不过,这个方案的缺点也比较明显:
- 需要的开发工作量比较大。我们举例的语句还算比较简单,但如果涉及复杂操作,比如 group by,甚至 join 这样的操作时,对中间层的开发能力要求比较高;
- 对 proxy 端的压力比较大,尤其是很容易出现内存不够用和 CPU 瓶颈问题。
为什么临时表可以重用?
表中数据的存放方式在不同 MySQL 版本中的不同处理方式
- 在 5.6 以及之前的版本里,MySQL 会在临时文件目录下创建一个相同前缀、以 .ibd 为后缀的文件,用来存放数据文件;
- 而从 5.7 版本开始,MySQL 引入了一个临时文件表空间,专门用来存放临时文件的数据。因此,我们就不需要创建 ibd 文件了。
MySQL 维护数据表时包含物理文件和内存里的表
- 一个普通表的
table_def_key
的值是由 “库名 + 表名” 得到的,所以如果你要在同一个库下创建两个同名的普通表,创建第二个表的过程中就会发现table_def_key
已经存在了; - 而对于临时表,
table_def_key
在 “库名 + 表名” 基础上,又加入了 “server_id+thread_id”。
临时表和主备复制
MySQL 记录 binlog 时将主库执行语句的线程编号写到 binlog 中
- session A 的临时表 t1,在备库的 table_def_key 就是:库名 +t1+ “M 的 serverid” + “session A 的 thread_id”;
- session B 的临时表 t1,在备库的 table_def_key 就是:库名 +t1+“M 的 serverid” + “session B 的 thread_id”。
末了
重新总结了一下文中提到的内容:临时表一般用于处理比较复杂的计算逻辑、在 binlog_format=‘row’ 时临时表的操作不记录到 binlog 中、用户自建的是用户临时表,系统自建的是内部临时表。