首先需要搞清楚一个容易误解的问题,那就是:临时表就是内存表,这两个概念是不同的。

  • 内存表。指使用Memroy引擎的表,这种表的数据都保存在内存里,系统重启的时候会被清空,但是表结构还在。
  • 临时表。可以使用各种引擎类型。如果使用InnoDb有你请或者MyISAM引擎的临时表,数据是可以写到磁盘上的。当然临时表也可以使用Memory引擎。

临时表的特征

临时表在使用上有如下几个特点:

  1. 建表语法是create temporary table …。
  2. 一个临时表只对创建它的session可见,对其他线程不可见。
  3. 临时表可以与普通表同名。
  4. 有同名的临时表和普通表,优先访问临时表。
  5. show tables命令不显示临时表。

临时表的应用

由于不用担心线程之间的重名冲突,临时表经常被用在复杂查询优化过程中。分库分表系统的跨库查询就是一个典型的使用场景。

对于一些复杂的查询,可能需要在各个实例中先查询出结果,然后再proxy层进行操作,但是这样对proxy的压力比较大。另一种思路就是把分库拿到的数据汇总的一个Mysql实例的一个表中,然后再在这个汇总实例上做逻辑操作。

为什么临时表可以重名

不同的线程可以创建同名的临时表。这是因为临时表的表结构定义文件frm文件会在临时文件目录下创建#sql{进程id}_{线程id}_序列号前缀的文件。5.6版本会创建一个前缀相同,存放数据的.ibd文件来存放数据。5.7开始引入了一个临时文件表空间,专门用来存放临时文件的数据。

所以不同线程创建的不同的临时表对应的文件在磁盘中对应的文件名是不同的。并且在内存中用于区分表的table_def_key,对于临时表来说是携带了thread_id的,所以也不会冲突。

临时表与主备复制

binlog设置为row格式,那么跟临时表有关的语句就不会记录到binlog中。

为statement/mixed格式时,才会记录到binlog中。

在主库不同的线程创建同名的临时表是没有问题的,但是备库的日志线程是公用的是如何处理的呢?备库在执行的时候,也要把传递过来的两个主库不同线程的同名临时表当作两个不同的临时表来处理。

mysql记录binlog的时候,会把主库执行这个语句的线程id写到binlog中,这样在备库的应用线程中就能够直到执行每个语句的主库线程id,并利用这个线程id来构造临时表的table_def_key。