【轉載】MySQL之臨時表和記憶體表
今天(2013-10-17)又看了一篇很久以前的部落格文章,題目是《 How to eliminate temporary tables in MySQL 》,裡面的一些觀點和結論摘錄如下:
- to make statement-based replication reliable is eliminate temporary tables.
- true temporary tables are created with CREATE TEMPORARY TABLE, and internal temporary tables are created internally by MySQL for sorting or processing subqueries.
- replace temporary tables with real tables in the systems by not naming tables randomly.
=========== 我是分割線 ============
今天(2013-10-11)看了另外一邊部落格文章,感覺之前記錄的內容似乎有些地方說的不太對。這裡的內容來自 MySQL 官網翻譯。
MySQL 如何使用內部臨時表?
在一些情況下,伺服器會在處理 query 的時候建立內部臨時表。這種表有兩種存在形式:
- 位於記憶體中,使用 MEMORY 儲存引擎(記憶體臨時表);
- 位於磁碟上,使用 MyISAM 儲存引擎(磁碟臨時表)。
伺服器可能在最初建立的是記憶體臨時表,之後當其變大到一定程度時再轉變為磁碟臨時表。對於伺服器何時建立內部臨時表或者臨時表使用哪種儲存引擎,使用者沒有直接控制的能力。
【伺服器可能會建立臨時表的場景】
1)ORDER BY 子句和 GROUP BY 子句不同,
例如:ORDERY BY price GROUP BY name;
2)在 JOIN 查詢中,ORDER BY 或者 GROUP BY 使用了不是第一個表的列
例如:SELECT * from TableA, TableB ORDER BY TableA.price GROUP by TableB.name
3)ORDER BY 中使用了 DISTINCT 關鍵字
ORDERY BY DISTINCT(price)
4)SELECT 語句中指定了 SQL_SMALL_RESULT 關鍵字
SQL_SMALL_RESULT 的意思就是告訴 MySQL,結果會很小,請直接使用記憶體臨時表,不需要使用索引排序
SQL_SMALL_RESULT 必須和 GROUP BY、DISTINCT 或 DISTINCTROW 一起使用
一般情況下,我們沒有必要使用這個選項,讓 MySQL 伺服器選擇即可。
5)由 FROM 語句中的子查詢產生的派生表
6)由於子查詢或者 semi-join materialization 所建立的表
【直接使用磁碟臨時表的場景】
- 表包含 TEXT 或者 BLOB 列;
- GROUP BY 或者 DISTINCT 子句中包含長度大於 512 位元組的列;
- 使用 UNION 或者 UNION ALL 時,SELECT 子句中包含大於 512 位元組的列;
【臨時表相關配置】
- tmp_table_size: 指定系統建立的記憶體臨時表最大大小;
- max_heap_table_size: 指定使用者建立的記憶體表的最大大小;
注意:最終的系統建立的記憶體臨時表大小是取上述兩個配置值的最小值。
伺服器可能在最初建立的是記憶體臨時表,之後當其變大到一定程度時再轉變為磁碟臨時表。這種表與通過 CREATE TABLE 顯式 建立的 MEMORY 記憶體表是不同的:對於後者,系統變數 max_heap_table_size 決定的是 MEMORY 記憶體表允許的最大大小,而不會出現向磁碟錶轉變的動作。
當伺服器建立了內部臨時表後(無論是在記憶體中還是在磁碟上),狀態變數 Created_tmp_tables 都會增加。如果伺服器建立了臨時表在磁碟上(無論是初始建立在磁碟還是後來轉化到磁碟), 狀態變數 Created_tmp_disk_tables 的值都會增加。
=========== 我是分割線 ============
mysql 複製和臨時表 temporary table
當你建立臨時表的時候,你可以使用 temporary 關鍵字。如:
1
|
create temporary table tmp_table( name varchar (10) not null ,passwd char (6) not null )
|
臨時表只在當前連線可見,當這個連線關閉的時候,會自動 drop 。這就意味著你可以在兩個不同的連線裡使用相同的臨時表名,並且相互不會衝突,或者使用已經存在的表,但不是臨時表的表名。(當這個臨時表存在的時候,存在的表被隱藏了,如果臨時表被 drop,存在的表就可見了)。建立臨時表你必須有 create temporary table 許可權。
下面幾點是臨時表的限制:
- 臨時表只能用在 memory、myisam、merge 或者 innodb 儲存引擎中;
- 臨時表不支援 mysql cluster(簇);
-
在同一個 query 語句中,你只能查詢一次臨時表。例如:下面的就不可用;
12mysql>
SELECT
*
FROM
temp_table, temp_table
AS
t2;
ERROR 1137: Can
`t reopen table: `
temp_table`
- 如果在一個儲存函式裡,你用不同的別名查詢一個臨時表多次,或者在這個儲存函式裡用不同的語句查詢,這個錯誤都會發生;
- show tables 語句不會列舉臨時表;
-
你不能用 rename 來重新命名一個臨時表。但是,你可以 alter table 代替:
1mysql>
ALTER
TABLE
orig_name RENAME new_name;
在資料庫複製中使用臨時表也有問題,詳情參看 Section 16.4.1, “Replication Features and Issues”。
複製和臨時表
為了避免出現臨時表複製問題,當臨時表開啟時,不要直接停止 slave 服務。而是用下面的步驟代替:
- 使用 stop slave sql_thread 語句;
- 使用 show status 檢視 Slave_open_temp_tables 的值;
- 如果這個值不是 0 ,使用 start slave sql_thread 重啟從庫 SQL 執行緒,一會兒後再重複執行這個步驟;
- 當這個值是 0 時,使用 mysqladmin shutdown 命令停止 slave 。
預設,所有的臨時表都是被複制的,無論是否匹配 –replicate-do-db、–replicate-do-table 或者 –replicate-wild-do-table,複製臨時表都會發生。但是,–replicate-ignore-table 和 –replicate-wild-ignore-table 兩個選項是用來忽略臨時表的。
如果你不想複製某些臨時表,請使用 –replicate-wild-ignore-table 選項。如 –replicate-wild-ignore-table=foo%.bar% 意思是告訴 slave 執行緒不要複製匹配以 foo 開頭和以 bar 開頭的表。
下面是轉自網上某人的配置資訊:
master端配置:
1
2
3
4
5
6
7
8
9
|
[mysqld] #Master start
#日誌輸出地址 主要同步使用
log-bin= /var/log/mysql/updatelog
#同步資料庫
binlog- do -db=cnb
#主機id 不能和從機id重複
server- id =1
#Master end
|
slave端配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
[mysqld] #Slave start
#從機id,區別於主機id
server- id =2
#主機ip,供從機連線主機用
master-host=192.168.0.24
#主機埠
master-port=3307
#剛才為從機複製主機資料新建的賬號
master-user=slave
#剛才為從機複製主機資料新建的密碼
master-password=123456
#重試間隔時間10秒
master-connect-retry=10
#需要同步的資料庫
replicate- do -db=cnb
#啟用從庫日誌,這樣可以進行鏈式複製
log-slave-updates
#從庫是否只讀,0表示可讀寫,1表示只讀
read -only=1
#只複製某個表
#replicate-do-table=tablename
#只複製某些表(可用匹配符)
#replicate-wild-do-table=tablename%
#只複製某個庫
#replicate-do-db=dbname
#不復制某個表
#replicate-ignore-table=tablename
#不復制某些表
#replicate-wild-ignore-table=tablename%
#不復制某個庫
#replicate-ignore-db=dbname
#Slave end
|
=========== 我是分割線 ============
基於mysql主從複製測試對臨時表和記憶體表的支援
臨時表測試:
1. 在主伺服器上
a. 建立臨時表 tmp1
1
|
create temporary table tmp1( id int not null);
|
b. 插入資料
1
|
mysql> insert into tmp1( id ) values(26);
|
c. 檢視資料
1
2
3
4
5
6
7
|
mysql> select * from tmp1;
+----+ | id |
+----+ | 23 | +----+ 1 row in set (0.00 sec)
|
在從伺服器上檢視:
1) 從伺服器連線主伺服器的狀態是否正常;
1
|
show slave statusG |
2)檢視是否同步了臨時表:
1
2
|
mysql> select * from tmp1;
ERROR 1146 (42S02): Table `cacti.tmp1` doesn`t exist
|
2. 在主伺服器上刪除 tmp1:
1
|
drop table tmp1; |
從伺服器沒有報錯!!!
記憶體表測試:
主伺服器上操作:
a. 建立記憶體表 tmp_test2
1
2
3
4
|
CREATE TABLE tmp_test2 (
Id int (11) AUTO_INCREMENT,
name varchar (255)
) ENGINE=MEMORY ; |
b. 插入資料
1
2
|
insert into tmp_test2( id )
values(10); |
c. 檢視資料
1
2
3
4
5
6
7
|
mysql> select * from tmp_test2;
+------+------+ | id | name |
+------+------+ | 10 | NULL | +------+------+ 1 row in set (0.00 sec)
|
在從伺服器上檢視狀態:
1) 從伺服器連線主伺服器狀態是否正常
1
|
show slave statusG |
2)檢視資料
1
2
3
4
5
6
7
|
mysql> select * from tmp_test2;
+------+------+ | id | name |
+------+------+ | 10 | NULL | +------+------+ 1 row in set (0.00 sec)
|
2. 在主伺服器上刪除 tmp_test2 表:
1
|
drop table tmp_test2; |
之後會發現,從服務上 tmp_test2 表也刪除了,從伺服器連線主伺服器狀態正常。
注:以上實驗不能說明臨時表不會在主從之間被複制、記憶體表會在主從之間複製。因為臨時表在主從之間是否會被複制有一些前提條件要約束的!
=========== 我是分割線 ============
臨時表在MySQL的複製中的處理
背景:在應用過程中,同事直接關閉了作為 slave 的 MySQL server 導致了臨時表問題。
在 MySQL5.1 手冊(6.7. 複製特性和已知問題)中提到,關閉 slave 的正確流程(個人認為在 4 步驟只啟動slave_SQL 執行緒好一些):
- 執行 STOP SLAVE 語句。
- 使用 SHOW STATUS 檢查 slave_open_temp_tables 變數的值。
- 如果值為 0,使用 mysqladmin shutdown 命令關閉從伺服器。
- 如果值不為 0,用 START SLAVE 重啟從伺服器執行緒。
- 後面再重複該程式看下次的運氣是否好一些。
slave_open_temp_tables 的值顯示,當前 slave 建立了多少臨時表。
提出幾個問題:
- 關掉slave的mysqld, 那臨時表肯定是不存在了,這樣再次start slave,slave_sql 執行緒執行bin-log時,肯定會出現找不臨時表的錯誤,
- 這就為什麼手冊中會提出以上操作流程了,這個問題容易理解。
- 眾所周知,MySQL臨時表只是當前connection有效(沒有全域性臨時表),當connection斷開,此臨時也就會被刪除,也就不存在了。
- MySQL 5.1的replication,slave的sql執行緒只有一個,那stop slave後,slave_sql_thread也就停止了,那在Slave上建立的臨時表應該隨之刪除,
- 但從上面步驟來看,說明Stop slave後, 臨時表還是存在的,這是為什麼呢?
- 如果Slave不停止,那由slave建立的臨時是如何正常刪除的? 它們在slave上的儲存形式又是怎麼樣的?
以下簡單分析一下 2,3 問題。
分析:
1,臨時表只對當前會話可見,連線斷開時,自動刪除!
2,檢視臨時表,在Master的binlog中的記錄形式:
2.1 MySQL 對臨時表的複製,如果在 mixed 的 binlog_format 情況下,會以 Statement 的形式記錄到 binlog中,當然也可以用 Row 形式 ,因為臨時表是基於 Session 的(也可以說是 Connection 的),所以在複製中,MySQL 會把執行緒 ID 新增到臨時表操作的事件中 ,此時的臨時表是屬於某個正在執行的 Thread 。 通過 mysqlbinlog 來檢視 binlog ,可以看到事件上繫結了 thread_id=297 就是這個臨時表的 宿主執行緒,當然你也可以用 Show processlist; 來檢視這個執行緒。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# at 106 #120318 1:42:30 server id 1 end_log_pos 291 Query thread_id=297 exec_time=0 error_code=0 use rep/*!*/; SET TIMESTAMP=1332006150/*!*/; SET @@session.pseudo_thread_id=297/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!C latin1 * // *!*/;
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; create temporary table cache2( id int unsigned not null, value char(10) not null default `` , primary key( id ) )engine=myisam
/*!*/; show processlist; | 297 | root | localhost | rep | Query | 0 | NULL | show processlist |
2.2 從 Master 的 binlog 可以看到,有一個 SET @@session.pseudo_thread_id=297,這個記錄 salve 的Sql_thread 在執行此 binlog 時, 會建立一個 id 號為 297 的”偽執行緒”, 這樣在 slave 上建立的此臨時表 cache2的宿主執行緒就此偽執行緒。
2.3 當 stop slave 後,Slave_SQL 執行緒已經關閉,但此時在 Slave 的臨時表是還存在的,可以通過在 Slave 上檢視 Status 變數 Slave_open_temp_tables,其實是不為 0 的,也就說由 Master 複製來的臨時表還存在,因為這些臨時表是所屬於 Master 上建立臨時表的 Thread 的 Thread_ID 對應的 pseudo_thread,所以雖然Slave_SQL connection 已經斷開,但臨時表是還存在的。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
mysql> show status like `%slave%` ;
+----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Com_show_slave_hosts | 0 | | Com_show_slave_status | 0 | | Com_slave_start | 0 | | Com_slave_stop | 0 | | Slave_open_temp_tables | 3 | | Slave_retried_transactions | 0 | | Slave_running | ON | +----------------------------+-------+ 7 rows in set (0.00 sec)
|
對於問題 2, 為何 slave sql thread 停掉後,臨時表還存在的原因。
3, Slave 中的臨時是如何刪除的呢?
當在 Master 上的、建立此臨時表的 Session 斷開後,binlog 會記錄一個 Drop 臨時表的事件, 這樣 Slave 對應的臨時表也就被刪除了,可以檢視臨時的狀態變數可得。從下面可以看,在我測試環境中 Master 上 thread_id=297 的這個 connection,一共建立了 3 個臨時表,當退出 mysql 後,Master 的 binlog 中會記錄一個 Drop temporary table 的事件。
1
2
3
4
5
6
7
8
|
#120318 1:45:53 server id 1 end_log_pos 734 Query thread_id=297 exec_time=0 error_code=0 SET TIMESTAMP=1332006353/*!*/; /*!C utf8 * // *!*/;
SET @@session.character_set_client=33,@@session.collation_connection=8,@@session.collation_server=8/*!*/; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `cache3`,`cache2`,`cache` /*!*/; DELIMITER ; # End of log file |
當 slave 的 slave_sql_thread 執行此事件,也就把剛才建立的臨時表刪除了。
4, Slave 建立的臨時表放在哪裡呢?
MySQL 建立的臨時表的檔案,其實是放在 show variables like `tmp_dir` 這個變數指定的目錄下。 預設情況是下在 /tmp 目錄下。
1
2
|
-rw-rw---- 1 mysql mysql 98304 Mar 23 05:39 #sql2625_18_0.ibd
-rw-rw---- 1 mysql mysql 8586 Mar 23 05:39 #sql2625_18_0.frm
|
同時也會在slave上的/tmp目錄下找到
1
2
|
-rw-rw---- 1 mysql mysql 8586 Mar 24 18:28 #sqld0b_7_2.frm
-rw-rw---- 1 mysql mysql 98304 Mar 24 18:28 #sqld0b_7_2.ibd
|
也可以根據mysqld開啟的檔案來檢視。
5,關於臨時表有兩個問題:
5.1 在重新啟動 Slave 的 mysqld 服務時,Stop Slave 後,一定要檢查 Slave_open_temp_tables 這個狀態值是否已經是 0,如果不是, 要重新 start slave, 再 stop slave,檢視,直接是 0 後,才 stop mysql 。因為 mysql 重新啟動後,在 Slave 上的所有臨時表都沒有了,這樣重新進行復制時, 後面還有對臨時表的操作的 binlog 事件,因為 Slave 上的臨時表已不存在,此時肯定會出錯了。
5.2 在用 binlog 進行 point_in_time 恢復資料庫時,一定要注意,把所有的 binlog 放在同一個 session 裡面執行,否則可能導致臨時表操作失敗。
相關文章
- mysql臨時表和記憶體表MySql記憶體
- 記憶體(memory)表和臨時(temporary)表之瞭解記憶體
- MySQL-37:記憶體臨時表MySql記憶體
- 記憶體表和臨時表的區別記憶體
- MySQL之臨時表MySql
- mysql cluster ndb 記憶體表和磁碟表MySql記憶體
- MySQL臨時表MySql
- mysql最大表記憶體MySql記憶體
- mysql 建立臨時表MySql
- ORACLE臨時表和SQLSERVER臨時表異同OracleSQLServer
- mysql複製和記憶體引擎的表MySql記憶體
- 排序sort area 記憶體不足會用到臨時表空間排序記憶體
- mysql binlog_format和臨時表MySqlORM
- MySQL 中的臨時表MySql
- MYSQL SELECT INTO臨時表MySql
- TimesTen臨時(記憶體)空間使用和調整臨時(記憶體)空間記憶體
- SQLServer表變數和臨時表系列之概念篇SQLServer變數
- oracle-記憶體表(轉)Oracle記憶體
- SQLServer臨時表和表變數系列之踢館篇SQLServer變數
- mysql的內部臨時表MySql
- mysql臨時表的問題MySql
- MySQL 5.7 新特性 共享臨時表空間及臨時表改進MySql
- 再議臨時表和表變數變數
- Oracle 基礎 ----臨時表和物件表Oracle物件
- mysql臨時表,臨時表空間,ibtmp1表空間暴增原因初探MySql
- oracle臨時表的用法(轉)Oracle
- MySQL InnoDB臨時表空間配置MySql
- MySQL臨時表的優化方案MySql優化
- MySQL 中的兩種臨時表MySql
- 記憶體表(FDMEMTABLE)記憶體
- 堆記憶體和棧記憶體詳解(轉載)記憶體
- optee記憶體管理和頁表建立記憶體
- SQL Server中的臨時表和表變數SQLServer變數
- mysql關於臨時表的總結MySql
- MySQL 中的myisam內部臨時表MySql
- PostgreSQL:臨時表SQL
- oracle臨時表Oracle
- Oracle 臨時表Oracle