join優(yōu)化用臨時表:有哪些特征堂氯,為什么它適合這個場景?
臨時表不是內存表
內存表牌废,Memory 引擎咽白,engine=memory。重啟清空鸟缕,表結構還在
臨時表晶框,各種引擎類型? 。InnoDB或MyISAM 臨時表懂从,寫到磁盤上授段。
一、臨時表的特性
1.? 建表 create temporary table
2.? 只能被創(chuàng)建session 訪問番甩,其他線程不可見侵贵。 A 創(chuàng)建臨時表 t, B 不可見
3.? 可與普通表同名
4.? show create 及增刪改查訪問的是臨時表缘薛。
5.? show tables 不顯示臨時表窍育。
適合join 優(yōu)化:
1.? 不同 session 臨時表可重名,多個 session 同時join宴胧,不需擔心表名重復漱抓,導致建表失敗
2.? 不需擔心刪除問題。普通表異常斷開/重啟恕齐,專門清理中間生成數(shù)據(jù)表乞娄。session 結束自動刪除臨時表
二、臨時表的應用
分庫分表跨庫查詢典型場景:大表 ht显歧,按字段 f仪或,拆分1024 個分表,分布到 32 個數(shù)據(jù)庫
一般都中間層 proxy追迟,也有直連溶其。
(1)分區(qū) key 以“減少跨庫和跨表查詢”為依據(jù)。大部分語句包含 f 等值條件敦间,f 做分區(qū)鍵瓶逃。 proxy 解析完 SQL 束铭,確定路由到哪個分表。分表規(guī)則(N%1024)
select v from ht? where f=N;
(1)另外索引 k厢绝,沒用分區(qū)字段 f
select v from ht? where k >= M order by t_modified desc limit 100;
思路1:proxy 層代碼實現(xiàn)排序
速度快契沫,拿到分庫數(shù)據(jù),內存中計算昔汉。缺點:
1.? 開發(fā)工作量大懈万。如 group by, join靶病,中間層開發(fā)能力高会通;
2.? ?proxy 端壓力大,內存不夠和 CPU 瓶頸問題娄周。
思路2:匯總表
匯總庫創(chuàng)建臨時表 temp_ht涕侈,包含 v、k煤辨、t_modified裳涛;各個分庫執(zhí)行
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; 得結果众辨。
實踐每個分庫計算量都不飽和端三,臨時表 temp_ht 放到 32 個分庫中某個上。查詢邏輯與圖 3 類似鹃彻。
三郊闯、為什么臨時表可重名?
3.1存儲區(qū)別不同
create temporary? table temp_t(id int primary key)engine=innodb;? ?//這時創(chuàng)建frm 文件保存表結構
放在臨時文件目錄下浮声,后綴是.frm虚婿,前綴是“#sql{進程 id}_{線程 id}_ 序列號”旋奢。 select @@tmpdir 顯示臨時文件目錄泳挥。
數(shù)據(jù)存放方式, MySQL 不同版本中處理方式:
5.6 以及之前的版本里至朗,.ibd 為后綴存放屉符,之后臨時文件表空間
t1 的 InnoDB 臨時表,MySQL 存儲上認為跟普通表 t1 不同锹引,session?A?的 id 是?4矗钟,session?B?的線程 id 是?5。磁盤上文件不重名嫌变。
3.2 內存區(qū)別不同
每個表都對應一個 table_def_key吨艇。普通表 table_def_key 值是由“庫名 + 表名”得到的,同庫下創(chuàng)建同名普通表腾啥,第二table_def_key 已存在东涡。
臨時表table_def_key 在“庫名 + 表名”基礎上冯吓,加了“server_id+thread_id”。
每個線程維護了自己臨時表鏈表疮跑。session 內操作组贺,先遍歷鏈表,臨時表優(yōu)先祖娘;結束時失尖,對鏈表里每個臨時表,執(zhí)行 “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 日志公黑,備庫執(zhí)行 insert into t_normal 報“表 temp_t 不存在”邑商。如的binlog_format=row,臨時表有關語句凡蚜,不記 binlog 里人断。
創(chuàng)建臨時表語句會傳到備庫執(zhí)行,同步線程(備庫)創(chuàng)建臨時表朝蜘。主庫線程退出自動刪除臨時表恶迈,備庫同步線程持續(xù)運行。主庫再寫DROP TEMPORARY TABLE 傳給備庫執(zhí)行谱醇。
4.1有趣的問題:
記錄 binlog時暇仲,不論create table還是 alter table都原樣記錄,空格都不變副渴。?
drop table t_normal奈附, binlog 就會寫成:
DROP TABLE? `t_normal` /* generated by server */ 統(tǒng)一標準格式。為什么煮剧?
drop table 命令可一次刪除多個表斥滤。上面例子binlog_format=row主庫 "drop table t_normal, temp_t" binlog 記錄:
DROP TABLE? `t_normal` /* generated by server */被服務端改寫過的命令。
備庫上沒有表 temp_t勉盅,重寫后再傳到備庫執(zhí)行佑颇,不會導致備庫同步線程停止。
4.2另外一個問題
主庫不同線程創(chuàng)建同名臨時表沒關系草娜,傳到備庫執(zhí)行是怎么處理的呢挑胸?
S 是 M 備庫。
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 語法路狮。什么原因虫啥?
rename table按照“庫名 / 表名.frm”去磁盤找,臨時表frm 文件在 tmpdir 目錄下奄妨,修改table_def_key涂籽,且文件名規(guī)則是“#sql{進程 id}_{線程 id}_ 序列號.frm”,報錯砸抛。
評論1
用連接池中連接來操作评雌,而連接不會釋放,保持長連接直焙。用臨時表會有問題嗎?景东。
會,“自動回收”用于“應用程序異常斷開奔誓、MySQL異常重啟”后斤吐,不需主動刪除表。
評論2
1.? session 結束DROP TEMPORARY TABLE厨喂,掉電和措,臨時表什么時候被清除
2. binlog 中記錄了臨時表的操作,session 不同蜕煌,從庫中訪問不到派阱,這樣做的意義是什么
作者回復: 1. 好問題,重啟后MySQL會掃描臨時目錄幌绍,把表都刪掉颁褂;
2. binlog是statement的時候,需同步備庫傀广,否則備庫上執(zhí)行insert into t_normal (select * from t_temp) 報錯