web-dev-qa-db-ja.com

MySQL:CREATE TEMPORARY TABLE SELECTを1回だけ実行しますか?

一部の選択データを含む一時テーブルを作成したい。

私の(奇妙な)問題は、同じクエリを複数回実行しなければならないことです。

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;

残念ながら、一時テーブルはすでに存在していますが、MySQLは2番目のクエリを実行します。

質問

  • テーブルが存在しない場合、一時テーブルの作成とSELECTクエリが実行されるだけであることをMySQLに伝える方法はありますか?
  • 多分if条件付き?
  • または、一時テーブルが存在する場合、いくつかの情報スキーマをチェックできますか?助けてくれてありがとう!

宜しくお願いします、

ティモ

5
Timo

これは、 _CREATE TEMPORARY TABLE_ を使用したテーブル作成の性質です

テーブルを作成するときにTEMPORARYキーワードを使用できます。 TEMPORARYテーブルは現在の接続に対してのみ表示され、接続が閉じられると自動的に削除されます。これは、2つの異なる接続が互いに、または同じ名前の既存の非TEMPORARYテーブルと競合することなく、同じ一時テーブル名を使用できることを意味します。 (既存のテーブルは、一時テーブルが削除されるまで非表示になります。)一時テーブルを作成するには、CREATE TEMPORARY TABLES特権が必要です。

私の推測では、次の一連のイベントを実行している必要があります。

  • あなたは_CREATE TEMPORARY TABLE_を実行しました
  • 終了したDB接続(一時テーブルがすぐに削除されます)
  • テーブルが存在しないため、_CREATE TEMPORARY TABLE_を再度実行する必要がありました

特にMySQLレプリケーションに関しては、この問題が多くの開発者を犠牲にしているのを見てきました。たとえば、_STOP SLAVE;_を実行すると、SQLスレッドが閉じます。 _CREATE TEMPORARY TABLE_で作成されたテーブルはすべて削除されます。 _START SLAVE;_を実行すると、INSERT、UPDATE、またはDELETEに必要なテーブルが存在しないため、MySQLレプリケーションは即座に中断します。リレーログでmysqlbinlogダンプを実行して元の_CREATE TEMPORARY TABLE_ステートメントを特定し、_CREATE TABLE_として実行して、テーブルがSQLスレッドを含む他のDB接続に引き続きアクセスできるようにする必要がありました_START SLAVE;_が再発行されます。

あなたの質問について

  • テーブルが存在しない場合、一時テーブルの作成とSELECTクエリが実行されるだけであることをMySQLに伝える方法はありますか?
  • 多分if条件付き?
  • または、一時テーブルが存在する場合、いくつかの情報スキーマをチェックできますか?

一時テーブルが存在するかどうかinformation_schemaを確認できません。 OSでは、 datadir に_.frm_が明示されていません。 tmpdir で定義されたフォルダで見つけることができます。

次に例を示します。_test.junk_という一時テーブルを作成し、テーブルの場所を探します。 (注:私はMySQL for Windowsを使用しています)

_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>
_

テーブルはINFORMATION_SCHEMA.TABLESに表示されません。 OSでテーブルを見つけましょう

_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>
_

Tmpdirフォルダーに一時テーブルがあります。 mysqlクライアントを閉じて_dir C:\Users\redwards\AppData\Local\Temp\*.frm_を実行すると、テーブルが消えました。

勧告

あなたは2つのことのいずれかを行うことができます

  1. 一時テーブルを作成し、データをロードして、同じDB接続を維持し、同じProcessIDでデータにアクセスします。
  2. _CREATE TEMPORARY TABLE IF NOT EXISTS_を実行します(これは実際には不適切な設計へのバンドエイドですが、問題を回避する可能性があります)。

UPDATE 2012-12-18 13:06 EDT

さらなる観察#1

同じDB接続を使用していてもこの問題が発生する場合は、これまでに言及されていない別の方法を使用してください。一時テーブルにインデックスを指定しました。一意のインデックスまたはプライマリキーである必要があります。

さらなる観察#2

操作を_CREATE TABLE ... SELECT_から_CREATE TABLE ... INSERT IGNORE_にシフトできます

さらなる観察#3

一時テーブルを使用する場合は、MyISAMを指定してください。 InnoDBは、クラッシュまたはDB接続の終了時に、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;
_

試してみる !!!

2
RolandoMySQLDBA