Here is the nature of table creation with CREATE TEMPORARY TABLE
You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current connection, and is dropped automatically when the connection is closed. This means that two different connections can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name. (The existing table is hidden until the temporary table is dropped.) To create temporary tables, you must have the CREATE TEMPORARY TABLES privilege.
My guess would be you must have done the following sequence of events:
- You ran
CREATE TEMPORARY TABLE
- Terminated DB Connection (which makes the temporary table drop immediately)
- You had to run
CREATE TEMPORARY TABLE
again because he table did not exist
I have seen this problem victimize many developers, especially when it comes to MySQL Replication. For example, if you run STOP SLAVE;
, the SQL Thread will close. Any tables create with CREATE TEMPORARY TABLE
will be dropped. When you run START SLAVE;
, MySQL Replication breaks instantly because the table needed for INSERTs, UPDATEs, or DELETEs no longer exist. I have had to perform mysqlbinlog dumps on relay logs to locate the original CREATE TEMPORARY TABLE
statements, run them as CREATE TABLE
in order for the table to remain accessible to other DB Connections, including the SQL Thread when START SLAVE;
is reissued.
As for your Questions
- Is there a way to tell MySQL that the creation of the temporary table and the
SELECT
query are just executed if the table does not exist?
- Maybe with an if-condition?
- Or can I check to some information schema if a temp-table exists?
You cannot check the information_schema for temp table existence. In the OS, there is no manifested .frm
in datadir
. You could find it in the folder defined in tmpdir
.
Here is an example: I will create a temporary table called test.junk
and try to locate the whereabouts of the table. (Note: I am using 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>
The table is not visible in INFORMATION_SCHEMA.TABLES. Let's locate the table in the 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>
There is the temp table, in the tmpdir folder. When I closed the mysql client and run dir C:\Users\redwards\AppData\Local\Temp\*.frm
, the table vanished.
RECOMMENDATION
You can do one of two things
- Create the temp table, load it with data, keep the same DB Connection around, and then access the data with the same ProcessID.
- Do
CREATE TEMPORARY TABLE IF NOT EXISTS
(This is really a band-aid to improper design but may circumvent the problem).
UPDATE 2012-12-18 13:06 EDT
Further Observation #1
If you stayed with the same DB Connection and still have this problem, here something else not previously mentioned: You gave the temp table an index. That should be a UNIQUE INDEX or PRIMARY KEY.
Further Observation #2
You could shift the operation from a CREATE TABLE ... SELECT
to CREATE TABLE ... INSERT IGNORE
Further Observation #3
If you want to use temp tables, please specify MyISAM. InnoDB has a tendency to leave pigeon holes in the data dictionary with ibdata1 in the event of a crash or upon DB Connection termination.
With these three(3) observations in mind, here is my recommended change
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;
Give it a Try !!!
A short answer would be: Yes, it affects performance.
A database stores it's data inside formatted database blocks. These blocks are the basis of all caching mechanism, so caches will store database blocks. Querying the database will move some read blocks into the query cache.
You can imagine, the smaller a block is, the more blocks can stay safely inside the caches without having to drop them for new blocks from new queries.
However, I'd say that in many scenarios that store data this way, performance differences of the kind I described might not be the most prominent factor for the underlying system. A benchmark might find differences, but for a system to react noticeably faster you need at least 10% faster responses (the number differs from study to study), and I'm not certain excluding the text column to it's own table will give you that.
On the other hand, if the column would be indexed, that might make matters different. But as I see no index other than the primary key, I see no reason to refactor here - other than that such a column is considered bad practice.
Best Answer
mysql_query() returns false only when there is something wrong with your query and it fails to execute. Otherwise, the return value is a resource which evaluates to success. That is your code always echoes "Account Exists". Check for the number of rows the SELECT statement fetched to determine whether the user exists or not.
Your code is also not secure. It is vulnerable to SQL injection. I would highly recommend NOT using mysql_* family of PHP functions. They are deprecated as of PHP 5.5.0 and will be removed in future releases. Consider switching over to mysqli_* family of functions or better use parameterized queries with PDO.
PDO: