內存表與臨時表區別
臨時表,一般是人手動創建。 內存表,是mysql自動創建和銷毀的。
內存表,指的是使用Memory引擎的表,建表語法:create table ... engine = memeory
表的數據存在內存里,系統重啟后會被清空,但是表的結構還在。
臨時表,可以使用各種引擎類型。如果使用的是InnoDB或者MyISAM引擎,寫數據是寫在磁盤上的。當然臨時表也可以使用Memory引擎。
臨時表特性
1、一個臨時表只能被創建它的session訪問,對于其他線程不可見,當此session結束時,會自動刪除臨時表
2、臨時表可以與普通表同名。如果同一個session里有同名的臨時表和普通表,使用show create語句以及增刪改查語句,訪問的是臨時表
3、show tables命令不顯示臨時表
臨時表的應用
由于不用擔心線程之間的重名沖突,臨時表經常被用在復雜查詢的優化過程中。其中,分庫分表系統的跨庫查詢就是一個典型的使用場景。
查詢語句到所有的分庫中查找滿足條件的行,然后統一做order by操作。
可以把各個分庫拿到的數據匯總到一個MySQL實例的一個表中,然后在這個匯總實例上做邏輯操作。如下:
至于臨時表的存儲位置,可以放在分庫中的某一個。
另外一個使用場景就是使用union(如果使用的是union all就不需要用了)。系統會先創建一個內部臨時表,執行第一個子查詢的結果放到臨時表中,執行第二個子查詢的結果先看看插入是否成功,成功則插入。最后從臨時表中按行取數據,然后返回結果,刪除臨時表。
臨時表可以重名的原因
無論是普通表還是臨時表,一個表都會對應一個table_def_def
- 一個普通表的
table_def_def
的值由"庫名+表名"得到。所以在同一個庫下創建兩個同名的普通表,會由重復性錯誤。 - 對于臨時表,
table_def_def
在“庫名+表名”的基礎上還加上了“server_id + thread_id”
在實現上,每個線程都維護了自己的臨時表鏈表,每次session內操作表的時候,先遍歷鏈表,檢查是否有這個名字的的臨時表,有就優先操作,否則再操作普通表。
session結束時,對鏈表中的每個臨時表,執行drop操作。這個操作也會被寫道binlog里用于主備復制。
臨時表的主備同步
row格式的binlog不會記錄臨時表相關語句,只有statement或者mixed格式才會記錄。
創建臨時表的語句會傳到備庫執行,因此備庫的同步線程就會創建這個臨時表。主庫在線程退出的時候會自動刪除臨時表,但是備庫同步線程還是在運行的,所以主庫還需要寫個DROP TEMPORARY TABLE
傳給備庫。
當主庫上兩個session創建了同名臨時表t1,這兩個語句被傳給備庫上。
主庫執行語句的線程id會被寫道binlog中,備庫可以用線程id構造臨時表的table_def_key
:
備庫名 + t1 + “主庫的serverid” + “session的thread_id”
,所以兩個表在備庫的應用線程不會沖突。