36 | 为什么临时表可以重名?

join优化用临时表:有哪些特征,为什么它适合这个场景?

临时表不是内存表

内存表,Memory 引擎,engine=memory。重启清空,表结构还在

临时表,各种引擎类型  。InnoDB或MyISAM 临时表,写到磁盘上。

一、临时表的特性

图 1 临时表特性示例  

1.  建表 create temporary table

2.  只能被创建session 访问其他线程不可见。 A 创建临时表 t, B 不可见

3.  可与普通表同名

4.  show create 及增删改查访问的是临时表

5.  show tables 不显示临时表。

适合join 优化:

1.  不同 session 临时表可重名,多个 session 同时join不需担心表名重复,导致建表失败

2.  不需担心删除问题。普通表异常断开/重启,专门清理中间生成数据表。session 结束自动删除临时表

二、临时表的应用

分库分表跨库查询典型场景:大表 ht,按字段 f,拆分1024 个分表,分布到 32 个数据库

图 2 分库分表简图

一般都中间层 proxy,也有直连

(1)分区 key 以“减少跨库和跨表查询”为依据。大部分语句包含 f 等值条件,f 做分区键。 proxy 解析完 SQL ,确定路由到哪个分表。分表规则(N%1024)

select v from ht  where f=N;

(1)另外索引 k,没用分区字段 f

select v from ht  where k >= M order by t_modified desc limit 100;

思路1:proxy 层代码实现排序

速度,拿到分库数据内存中计算。缺点:

1.  开发工作量大。如 group by, join,中间层开发能力高;

2.   proxy 端压力大内存不够CPU 瓶颈问题。

思路2:汇总表

汇总库创建临时表 temp_ht,包含 v、k、t_modified;各个分库执行

select  v,k,t_modified from ht_x where k >= M order by t_modified desc limit 100;结果插入temp_ht 表中;

select v from  temp_ht order by t_modified desc limit 100; 得结果。

图 3 跨库查询流程示意图

实践每个分库计算量都不饱和,临时表 temp_ht 放到 32 个分库中某个上。查询逻辑与图 3 类似。

三、为什么临时表可重名?

3.1存储区别不同

create temporary  table temp_t(id int primary key)engine=innodb;   //这时创建frm 文件保存表结构

放在临时文件目录下,后缀是.frm,前缀是“#sql{进程 id}_{线程 id}_ 序列号select @@tmpdir 显示临时文件目录。

数据存放方式, MySQL 不同版本中处理方式:

5.6 以及之前的版本里,.ibd 为后缀存放,之后临时文件表空间

t1 的 InnoDB 临时表,MySQL 存储上认为跟普通表 t1 不同,session A 的 id 是 4,session 的线程 id 是 5磁盘上文件不重名

图 4 临时表的表名

3.2 内存区别不同

每个表都对应一个 table_def_key。普通表 table_def_key 值是由“库名 + 表名”得到的,同库下创建同名普通表,第二table_def_key 已存在。

临时表table_def_key 在“库名 + 表名”基础上,加了“server_id+thread_id”。

每个线程维护了自己临时表链表。session 内操作,先遍历链表临时表优先;结束时,对链表里每个临时表,执行 “DROP TEMPORARY TABLE + 表名”,binlog 中也记录 DROP TEMPORARY TABLE 命令。

四、临时表和主备复制

写 binlog,意味备库需要。

create table  t_normal(id int primary key, c int)engine=innodb;/*Q1*/

create temporary  table temp_t like t_normal;/*Q2*/

insert into  temp_t values(1,1);/*Q3*/

insert into  t_normal select * from temp_t;/*Q4*/

如临时表操作不记录,备库只有 create table t_normal 表和 insert into t_normal select * from temp_t 的 binlog 日志,备库执行 insert into t_normal 报“表 temp_t 不存在”。如的binlog_format=row,临时表有关语句,不记 binlog 里。

创建临时表语句会传到备库执行,同步线程(备库)创建临时表。主库线程退出自动删除临时表,备库同步线程持续运行主库再写DROP TEMPORARY TABLE 传给备库执行。

4.1有趣的问题:

记录 binlog时,不论create table还是 alter table原样记录,空格都不变。 

drop table t_normal, binlog 就会写成:

DROP TABLE  `t_normal` /* generated by server */ 统一标准格式。为什么?

drop table 命令可一次删除多个表。上面例子binlog_format=row主库 "drop table t_normal, temp_t" binlog 记录:

DROP TABLE  `t_normal` /* generated by server */被服务端改写过的命令。

备库上没有表 temp_t,重写后再传到备库执行,不会导致备库同步线程停止

4.2另外一个问题

主库不同线程创建同名临时表没关系,传到备库执行是怎么处理的呢?

S 是 M 备库。

图 5 主备关系中的临时表操作  

table_def_key 不同,当做不同临时表处理。(主库线程 id 写到 binlog)

1.  A 临时表 t1,备库table_def_key 就是:库名 +t1+“M 的 serverid”+“session A thread_id”;

2.  B 临时表 t1,备库table_def_key 就是 :库名 +t1+“M 的 serverid”+“session B 的 thread_id”。

小结

临时表用法和特性。

处理比较复杂的计算逻辑。自己可见的,所以不需考虑重名问题。在自动删除

binlog_format='row’临时表不记录到 binlog 

思考题

临时表改名:alter table 可以,不能用 rename 语法。什么原因?

图 6 关于临时表改名的思考题

rename table按照“库名 / 表名.frm”去磁盘找,临时表frm 文件在 tmpdir 目录下,修改table_def_key,且文件名规则是“#sql{进程 id}_{线程 id}_ 序列号.frm”,报错。

评论1

用连接池中连接来操作,而连接不会释放,保持长连接。用临时表会有问题吗?

会,“自动回收”用于“应用程序异常断开、MySQL异常重启”后,不需主动删除表。

评论2

1.  session 结束DROP TEMPORARY TABLE,掉电,临时表什么时候被清除

2. binlog 中记录了临时表的操作,session 不同,从库中访问不到,这样做的意义是什么

作者回复: 1. 好问题,重启后MySQL会扫描临时目录,把表都删掉

2. binlog是statement的时候,需同步备库,否则备库上执行insert into t_normal (select * from t_temp) 报错

你可能感兴趣的:(36 | 为什么临时表可以重名?)