您的位置:首页 > 数据库 > MySQL

MySQL临时表

2021-04-12 00:16 976 查看

MySQL 临时表

MySQL 临时表在我们需要保存一些临时数据时是非常有用的。临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间。

临时表在MySQL 3.23版本中添加,如果你的MySQL版本低于 3.23版本就无法使用MySQL的临时表。不过现在一般很少有再使用这么低版本的MySQL数据库服务了。

MySQL临时表只在当前连接可见,如果你使用PHP脚本来创建MySQL临时表,那每当PHP脚本执行完成后,该临时表也会自动销毁。

如果你使用了其他MySQL客户端程序连接MySQL数据库服务器来创建临时表,那么只有在关闭客户端程序时才会销毁临时表,当然你也可以手动销毁。

实例

以下展示了使用MySQL 临时表的简单实例,以下的SQL代码可以适用于PHP脚本的mysql_query()函数。

>mysql> CREATE TEMPORARY TABLE SalesSummary (
    -> product_name VARCHAR(50) NOT NULL
    -> , total_sales DECIMAL(12,2) NOT NULL DEFAULT 0.00
    -> , avg_unit_price DECIMAL(7,2) NOT NULL DEFAULT 0.00
    -> , total_units_sold INT UNSIGNED NOT NULL DEFAULT 0
);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO SalesSummary
    -> (product_name, total_sales, avg_unit_price, total_units_sold)
    -> VALUES
    -> ('cucumber', 100.25, 90, 2);

mysql> SELECT * FROM SalesSummary;
+--------------+-------------+----------------+------------------+
| product_name | total_sales | avg_unit_price | total_units_sold |
+--------------+-------------+----------------+------------------+
| cucumber     |      100.25 |          90.00 |                2 |
+--------------+-------------+----------------+------------------+
1 row in set (0.00 sec)

 

当你使用 SHOW TABLES命令显示数据表列表时,你将无法看到 SalesSummary表。

如果你退出当前MySQL会话,再使用 SELECT命令来读取原先创建的临时表数据,那你会发现数据库中没有该表的存在,因为在你退出时该临时表已经被销毁了。

删除MySQL 临时表

默认情况下,当你断开与数据库的连接后,临时表就会自动被销毁。当然你也可以在当前MySQL会话使用 DROP TABLE 命令来手动删除临时表。

以下是手动删除临时表的实例:

mysql> CREATE TEMPORARY TABLE SalesSummary (
    -> product_name VARCHAR(50) NOT NULL
    -> , total_sales DECIMAL(12,2) NOT NULL DEFAULT 0.00
    -> , avg_unit_price DECIMAL(7,2) NOT NULL DEFAULT 0.00
    -> , total_units_sold INT UNSIGNED NOT NULL DEFAULT 0
);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO SalesSummary
    -> (product_name, total_sales, avg_unit_price, total_units_sold)
    -> VALUES
    -> ('cucumber', 100.25, 90, 2);

mysql> SELECT * FROM SalesSummary;
+--------------+-------------+----------------+------------------+
| product_name | total_sales | avg_unit_price | total_units_sold |
+--------------+-------------+----------------+------------------+
| cucumber     |      100.25 |          90.00 |                2 |
+--------------+-------------+----------------+------------------+
1 row in set (0.00 sec)
mysql> DROP TABLE SalesSummary;
mysql>  SELECT * FROM SalesSummary;
ERROR 1146: Table 'RUNOOB.SalesSummary' doesn't exist

 


 

MySQL中临时表的基本创建与使用教程

当工作在非常大的表上时,你可能偶尔需要运行很多查询获得一个大量数据的小的子集,不是对整个表运行这些查询,而是让MySQL每次找出所需的少数记录,将记录选择到一个临时表可能更快些,然后在这些表运行查询。

创建临时表很容易,给正常的CREATE TABLE语句加上TEMPORARY关键字:

CREATE TEMPORARY TABLE tmp_table (
 name VARCHAR(10) NOT NULL,
 value INTEGER NOT NULL
)

 

临时表将在你连接MySQL期间存在。当你断开时,MySQL将自动删除表并释放所用的空间。当然你可以在仍然连接的时候删除表并释放空间。

DROP TABLE tmp_table

 

如果在你创建名为tmp_table临时表时名为tmp_table的表在数据库中已经存在,临时表将有必要屏蔽(隐藏)非临时表tmp_table。

如果你声明临时表是一个HEAP表,MySQL也允许你指定在内存中创建它:

CREATE TEMPORARY TABLE tmp_table (  
 name VARCHAR(10) NOT NULL,
 value INTEGER NOT NULL
) TYPE = HEAP

 

因为HEAP表存储在内存中,你对它运行的查询可能比磁盘上的临时表快些。然而,HEAP表与一般的表有些不同,且有自身的限制。详见MySQL参考手册。

正如前面的建议,你应该测试临时表看看它们是否真的比对大量数据库运行查询快。如果数据很好地索引,临时表可能一点不快。

临时表再断开于mysql的连接后系统会自动删除临时表中的数据,但是这只限于用下面语句建立的表:

定义字段:

CREATE TEMPORARY TABLE tmp_table (
 name VARCHAR(10) NOT NULL,
 value INTEGER NOT NULL 
)

 

直接将查询结果导入临时表

CREATE TEMPORARY TABLE tmp_table SELECT * FROM table_name

 

另外mysql也允许你在内存中直接创建临时表,因为是在内存中所有速度会很快,语法如下:

CREATE TEMPORARY TABLE tmp_table (
 name VARCHAR(10) NOT NULL,
 value INTEGER NOT NULL
) TYPE = HEAP

 

 从上面的分析可以看出临时表的数据是会被清空的,你断开了连接就会被自动清空,但是你程序中不可能每发行一次sql就连接一次数据库吧(如果是这样的话,那就会出现你担心的问题,如果不是就没有问题),因为只有断开数据库连接才会被清空数据,在一个数据库连接里面发行多次sql的话系统是不会自动清空临时表数据的。

只有在当前连接情况下, TEMPORARY 表才是可见的。当连接关闭时, TEMPORARY 表被自动取消。这意味着两个不同的连接可以使用相同的临时表名称,同时两个临时表不会互相冲突,也不与原有的同名的非临时表冲突。(原有的表被隐藏,直到临时表被取消时为止。)必须拥有 CREATE TEMPORARY TABLES 权限,才能创建临时表。可以通过指定 ENGINE|TYPE = MEMORY; 来指定创建内存临时表。

如果表已存在,则使用关键词 IF NOT EXISTS 可以防止发生错误。注意,原有表的结构与 CREATE TABLE 语句中表示的表的结构是否相同,这一点没有验证。注释:如果在 CREATE TABLE...SELECT 语句中使用 IF NOT EXISTS ,则不论表是否已存在,由 SELECT 部分选择的记录都会被插入。

DROP TEMPORARY TABLE 语句只取消 TEMPORARY 表,语句不会终止正在进行中的事务。在采用连接池的情况下,为防止多次 CREATE 、 DROP TEMPORARY TABLE 带来的性能瓶颈,可以使用 CREATE IF NOT EXISTS + TRUNCATE TABLE 的方式来提升性能。

临时表支持主键、索引指定。在连接非临时表查询可以利用指定主键或索引来提升性能。

CREATE PROCEDURE sp_test_tt(IN i_chars VARCHAR(50),OUT o_counts BIGINT)
BEGIN
     create temporary table if not exists tmpTable – 不存在则创建临时表
     (
      objChk varchar(255) primary key,
      ModelName varchar(50),
      Operator varchar(500),
      PModelName varchar(50)
     );
     truncate TABLE tmpTable; -- 使用前先清空临时表。
 
     insert into tmpTable values(i_chars,i_chars,i_chars,i_chars);
     insert into tmpTable values(i_chars,i_chars,i_chars,i_chars); -- 语句1
     select * from tmpTable; -- 语句2
     select count(*) into o_counts from tmpTable; -- 语句3
END;

 

上述代码语句 1 返回临时表中所有数据,语句 2 将总记录数写入输出参数。 truncate 语句放在 create 之后,而不是整个存储过程最后,原因在于随后的语句 1 插入同样的值,二临时表 PK 校验将产生一个错误,则存储过程最终异常结束。综合异常处理,可以如下修改,以在每次存储过程调用完毕后清除临时表。
再来看一个例子:

CREATE PROCEDURE sp_test_tt(IN i_chars VARCHAR(50),OUT o_counts BIGINT)
BEGIN
     create temporary table if not exists tmpTable
     (
      objChk varchar(255) primary key,
      ModelName varchar(50),
      Operator varchar(500),
      PModelName varchar(50)
     ) ENGINE = MEMORY;
     begin
          declare exit handler for sqlwarning,NOT FOUND,SQLEXCEPTION set o_counts=-1;
          insert into tmpTable values(i_chars,i_chars,i_chars,i_chars);
          select * from tmpTable; -- 语句1
          select count(*) into o_counts from tmpTable;
     end;
     truncate TABLE tmpTable; -- 语句2
END;

 

虽然上述代码语句 2 最后 truncate table 清空了全部临时表数据,但前面语句 1 select 的数据结果集不会被清除。已通过 java 程序验证。

临时表可以解决二维数组输出的问题。但是,大批量的数据插入只能由程序采用循环来做。某些特殊情况下的输入数组,例如选择好的一组待删除数据的 ID 的输入,也只能利用循环来做。临时表也不适用于需要三维数组的情况。

通过CREATE TEMPORARY TABLE 创建的临时表,这种临时表称为外部临时表。这种临时表只对当前用户可见,当前会话结束的时候,该临时表会自动关闭。这种临时表的命名与非临时表可以同名(同名后非临时表将对当前会话不可见,直到临时表被删除)。

内部临时表

内部临时表是一种特殊轻量级的临时表,用来进行性能优化。这种临时表会被MySQL自动创建并用来存储某些操作的中间结果。这些操作可能包括在优化阶段或者执行阶段。这种内部表对用户来说是不可见的,但是通过EXPLAIN或者SHOW STATUS可以查看MYSQL是否使用了内部临时表用来帮助完成某个操作。内部临时表在SQL语句的优化过程中扮演着非常重要的角色, MySQL中的很多操作都要依赖于内部临时表来进行优化。但是使用内部临时表需要创建表以及中间数据的存取代价,所以用户在写SQL语句的时候应该尽量的去避免使用临时表。

内部临时表有两种类型:一种是HEAP临时表,这种临时表的所有数据都会存在内存中,对于这种表的操作不需要IO操作。另一种是OnDisk临时表,顾名思义,这种临时表会将数据存储在磁盘上。OnDisk临时表用来处理中间结果比较大的操作。如果HEAP临时表存储的数据大于MAX_HEAP_TABLE_SIZE(详情请参考MySQL手册中系统变量部分),HEAP临时表将会被自动转换成OnDisk临时表。OnDisk临时表在5.7中可以通过INTERNAL_TMP_DISK_STORAGE_ENGINE系统变量选择使用MyISAM引擎或者InnoDB引擎。

mysql的内存表和临时表

内存表:

session 1      
$ mysql -uroot      
root@(none) 10:05:06>use test      
Database changed      
root@test 10:06:06>CREATE TABLE tmp_memory (i INT) ENGINE = MEMORY;      
Query OK, 0 rows affected (0.00 sec)      
root@test 10:08:46>insert into tmp_memory values (1);      
Query OK, 1 row affected (0.00 sec)      
root@test 10:08:46>      


session2      
$ mysql -uroot test      
root@test 10:05:12>CREATE TABLE tmp_memory (i INT) ENGINE = MEMORY;      
ERROR 1050 (42S01): Table 'tmp_memory' already exists      
root@test 10:16:27>select * from tmp_memory;      
+------+      
| i |      
+------+      
| 1 |      
+------+      
row in set (0.00 sec)      

1. 多个session,创建表的名字不能一样

2. 一个session创建会话后,对其他session也是可见的
3. data目录下只有tmp_memory.frm ,表结构放在磁盘上,数据放在内存中
4. mysql 重启或者关闭后内存表里的数据会丢失,但是表结构仍然存在
5. 可以创建索引,删除索引,支持唯一索引
6. 不影响主备,主库上插入的数据,备库也可以查到
7. show tables 看得到表

临时表:

session1      
$ mysql -uroot test      
root@test 10:30:18>CREATE TEMPORARY TABLE tmp_table (name VARCHAR(10) NOT NULL,value INTEGER NOT NULL);      
Query OK, 0 rows affected (0.05 sec)      
root@test 10:31:54>select * from tmp_table;      
+--------+-------+      
| name | value |      
+--------+-------+      
| aaaaaa | 10 |      
+--------+-------+      
row in set (0.00 sec)      


session2      
root@test 10:20:13> CREATE TEMPORARY TABLE tmp_table (name VARCHAR(10) NOT NULL,value INTEGER NOT NULL);      
Query OK, 0 rows affected (0.02 sec)      


root@test 10:30:39>insert into tmp_table values ('bbbbbbb',10);      
Query OK, 1 row affected (0.01 sec)      


root@test 10:31:33>select * from tmp_table;      
+---------+-------+      
| name | value |      
+---------+-------+      
| bbbbbbb | 10 |      
+---------+-------+      
row in set (0.00 sec)      


root@test 10:31:43>exit      
Bye      
[1 Single:MS-Master db152011.sqa.cm6: mysql ~ ]      
$ mysql -uroot test      
root@test 10:32:17>select * from tmp_table;      
ERROR 1146 (42S02): Table 'test.tmp_table' doesn't exist      
root@test 10:32:22>      
root@test 10:32:23>      

1. 创建的表的名字可以一样 

2. 表结构和数据都放在内存中
3. 会话消失表结构和数据都消失
4. 可以创建索引,删除索引
5. 主库创建的表,备库查不到,
6. show tables 看不到表

使用内存表需要注意的事项

1. 内存表需要自己delete数据或者drop表;需要drop权限,这点比较危险

2. 内存表的表结构是保存在磁盘上的,如果多个session使用同一个表名,会存在冲突;如果不需要使用表名,如果使用一次都需要创建表结构,到时候会有很多小文件存在,不利于db的维护,dba清理表也有风险;

基于以上不适合用内存表

1. 临时表是会话级别的,即使多个session创建的表名一样,都相互不影响

2. 会话消失,所有的都消失,这点很不利于应用排查问题

另外这两个都需要消耗额外的内存空间,虽然db端可以忍受,但是不太可控;DB端还有这个参数:

max_tmp_tables 一个客户能同时保持打开的临时表的最大数量,这个值默认32,可以根据需要调整此值


 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: