MySQL:只执行一次 CREATE TEMPORARY TABLE SELECT?

Tim*_*imo 7 mysql if-not-exists temporary-tables

我想用一些选择数据创建一个临时表。

我的(奇怪的)问题是我必须多次执行相同的查询。

CREATE TEMPORARY TABLE IF NOT EXISTS cache (id int(11) NOT NULL, INDEX (id)) 
SELECT id FROM table WHERE xyz;

CREATE TEMPORARY TABLE IF NOT EXISTS cache (id int(11) NOT NULL, INDEX (id)) 
SELECT id FROM table WHERE xyz;
Run Code Online (Sandbox Code Playgroud)

不幸的是,尽管临时表已经存在,MySQL 还是执行了第二个查询。

问题

  • 有没有办法告诉 MySQL 临时表的创建和SELECT查询在表不存在的情况下才执行?
  • 也许有一个if条件?
  • 或者,如果存在临时表,我可以检查某些信息模式吗?感谢您的帮助!

此致,

蒂莫

Rol*_*DBA 4

这是表创建的本质CREATE TEMPORARY TABLE

创建表时可以使用 TEMPORARY 关键字。TEMPORARY 表仅对当前连接可见,并在连接关闭时自动删除。这意味着两个不同的连接可以使用相同的临时表名称,而不会相互冲突或与现有的同名非 TEMPORARY 表发生冲突。(现有表将被隐藏,直到临时表被删除。)要创建临时表,您必须具有 CREATE TEMPORARY TABLES 权限。

我的猜测是您一定已经完成了以下一系列事件:

  • 你跑了CREATE TEMPORARY TABLE
  • 终止数据库连接(这使得临时表立即删除)
  • 你必须CREATE TEMPORARY TABLE再次运行,因为他的表不存在

我看到这个问题让许多开发人员受害,尤其是在 MySQL 复制方面。例如,如果您运行STOP SLAVE;,SQL 线程将关闭。使用创建的任何表都CREATE TEMPORARY TABLE将被删除。当您运行时START SLAVE;,MySQL 复制会立即中断,因为 INSERT、UPDATE 或 DELETE 所需的表不再存在。我必须在中继日志上执行 mysqlbinlog 转储来定位原始CREATE TEMPORARY TABLE语句,运行它们,CREATE TABLE以便表仍然可供其他数据库连接访问,包括START SLAVE;重新发出时的 SQL 线程。

至于你的问题

  • SELECT有没有办法告诉MySQL,如果表不存在,则只执行临时表的创建和查询?
  • 也许有一个 if 条件?
  • 或者如果临时表存在,我可以检查某些信息模式吗?

您无法检查 information_schema 是否存在临时表。在操作系统中,没有体现.frm出来datadir。您可以在 中定义的文件夹中找到它tmpdir

下面是一个例子:我将创建一个名为的临时表test.junk并尝试定位该表的下落。(注:我使用的是 Windows 版 MySQL)

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.5.12-log MySQL Community Server (GPL)

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use test
Database changed
mysql> create temporary table junk (a int) engine=MyISAM;
Query OK, 0 rows affected (0.02 sec)

mysql> show create table junk\G
*************************** 1. row ***************************
       Table: junk
Create Table: CREATE TEMPORARY TABLE `junk` (
  `a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

mysql> select count(1) from information_schema.tables
-> where table_schema='test' and table_name='junk';
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.08 sec)

mysql> show variables like 'datadir';
+---------------+-----------------------+
| Variable_name | Value                 |
+---------------+-----------------------+
| datadir       | C:\MySQL_5.5.12\data\ |
+---------------+-----------------------+
1 row in set (0.00 sec)

mysql> show variables like 'tmpdir';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| tmpdir        | C:\Users\redwards\AppData\Local\Temp |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

该表在 INFORMATION_SCHEMA.TABLES 中不可见。让我们在操作系统中找到该表

C:\MySQL_5.5.12\data\test>cd
C:\MySQL_5.5.12\data\test

C:\MySQL_5.5.12\data\test>dir junk.*
 Volume in drive C has no label.
 Volume Serial Number is 2C92-485B

 Directory of C:\MySQL_5.5.12\data\test

File Not Found

C:\MySQL_5.5.12\data\test>dir C:\Users\redwards\AppData\Local\Temp\*.frm
 Volume in drive C has no label.
 Volume Serial Number is 2C92-485B

 Directory of C:\Users\redwards\AppData\Local\Temp

10/19/2012  11:04 AM             8,554 #sql7ac_3_0.frm
               1 File(s)          8,554 bytes
               0 Dir(s)  190,200,049,664 bytes free

C:\MySQL_5.5.12\data\test>dir C:\Users\redwards\AppData\Local\Temp\*.MY*
 Volume in drive C has no label.
 Volume Serial Number is 2C92-485B

 Directory of C:\Users\redwards\AppData\Local\Temp

10/19/2012  11:04 AM                 0 #sql7ac_3_0.MYD
10/19/2012  11:04 AM             1,024 #sql7ac_3_0.MYI
               2 File(s)          1,024 bytes
               0 Dir(s)  190,200,049,664 bytes free

C:\MySQL_5.5.12\data\test>
Run Code Online (Sandbox Code Playgroud)

tmpdir 文件夹中有临时表。当我关闭 mysql 客户端并运行时dir C:\Users\redwards\AppData\Local\Temp\*.frm,该表消失了。

推荐

你可以做两件事之一

  1. 创建临时表,向其加载数据,保持相同的数据库连接,然后使用相同的 ProcessID 访问数据。
  2. 这样做CREATE TEMPORARY TABLE IF NOT EXISTS(这实际上是针对不当设计的创可贴,但可能会规避问题)。

更新 2012-12-18 13:06 美国东部时间

进一步观察#1

如果您使用相同的数据库连接但仍然遇到此问题,这里还有一些先前未提及的内容:您为临时表提供了一个索引。那应该是唯一索引或主键。

进一步观察#2

您可以将操作从 a 转移CREATE TABLE ... SELECTCREATE TABLE ... INSERT IGNORE

进一步观察#3

如果要使用临时表,请指定MyISAM。如果发生崩溃或数据库连接终止,InnoDB 往往会在数据字典中留下 ibdata1 的鸽子洞。

考虑到这三(3)个观察结果,这是我建议的更改

CREATE TEMPORARY TABLE IF NOT EXISTS cache
(id int(11) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM;
INSERT IGNORE INTO cache SELECT id FROM table WHERE xyz;

CREATE TEMPORARY TABLE IF NOT EXISTS cache
(id int(11) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM;
INSERT IGNORE INTO cache SELECT id FROM table WHERE xyz;
Run Code Online (Sandbox Code Playgroud)

试一试 !!!