Bug #33381 | Temporary table created on disk when it should be in ram | ||
---|---|---|---|
Submitted: | 19 Dec 2007 19:27 | Modified: | 6 Oct 2009 16:32 |
Reporter: | J Rabbit | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Data Types | Severity: | S5 (Performance) |
Version: | 5.0.45, 5.0.52, 5.1.40 | OS: | Linux |
Assigned to: | CPU Architecture: | Any |
[19 Dec 2007 19:27]
J Rabbit
[19 Dec 2007 19:56]
Valeriy Kravchuk
Thank you for a bug report. Looks like this page, http://dev.mysql.com/doc/refman/5.0/en/internal-temporary-tables.html, should just be updated. This list: "Some conditions prevent the use of a MEMORY temporary table, in which case the server uses a MyISAM table instead: - Presence of a TEXT or BLOB column in the table - Presence of any column in a GROUP BY or DISTINCT clause larger than 512 bytes" should also include: - Presence of any column larger than 512 bytes in SELECT list if UNION or UNION ALL is used.
[19 Dec 2007 20:36]
Paul DuBois
Thank you for your bug report. This issue has been addressed in the documentation. The updated documentation will appear on our website shortly, and will be included in the next release of the relevant products. I have added the information provided by Valeriy.
[19 Dec 2007 20:49]
J Rabbit
That still doesn't quite explain it. If you change the encoding to utf8, then the maximum length of both columns can be more than 512 bytes despite the name column only being 512 characters. However, it still only creates a temporary table on disk if you use the 513 character column in the select list. It seems strange that the 512 byte limit exists at all, when the MEMORY storage engine is capable of storing varchar fields longer than this.
[21 Dec 2007 6:06]
Valeriy Kravchuk
Please, send the exact CREATE TABLE statement you had used when testing with utf8. Look: mysql> show create table test\G *************************** 1. row *************************** Table: test Create Table: CREATE TABLE `test` ( `id` int(11) NOT NULL, `name` varchar(512) NOT NULL, `description` varchar(513) NOT NULL ) ENGINE=MEMORY DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> (SELECT name FROM test WHERE id=1) -> UNION -> (SELECT name FROM test WHERE id=2); Field 1: `name` Catalog: `def` Database: `` Table: `` Org_table: `` Type: VAR_STRING Collation: latin1_swedish_ci (8) Length: 512 Max_length: 0 Decimals: 0 Flags: NOT_NULL 0 rows in set (0.03 sec) mysql> (SELECT description FROM test WHERE id=1) -> UNION -> (SELECT description FROM test WHERE id=2); Field 1: `description` Catalog: `def` Database: `` Table: `` Org_table: `` Type: BLOB Collation: latin1_swedish_ci (8) Length: 1539 Max_length: 0 Decimals: 0 Flags: NOT_NULL BLOB 0 rows in set (0.01 sec) The above is what I've got.
[20 Jan 2008 12:50]
J Rabbit
Using the UTF-8 version of the create table statement from the previous comment illustrates my point. I get the same output with --debug-info enabled: the name column in the result set is type VAR_STRING and the description column is type BLOB. If, as specified in the manual, the criteria for selecting between VAR_STRING and BLOB is whether the field is defined as more than 512 bytes, the name column should also be BLOB, as one UTF-8 character can be multiple bytes in length. If there is an error in the manual, and it should read "characters" rather than "bytes" (as suggested by the fact that no errors occur when processing the query on the name field without a temporary disk table even if you fill it with 512 multi-byte characters), that proves the underlying code can cope with having more than 512 bytes in a temporary memory table column. If the system does work ok with more 512 bytes of data in such a column, is necessary for the limit defining when to switch to a BLOB to remain hard-coded at 512 bytes/characters?
[6 Oct 2009 17:06]
Valeriy Kravchuk
Actually, this indeed looks like a server bug (verified with latest 5.1.40). Look: mysql> show create table test_utf8\G *************************** 1. row *************************** Table: test_utf8 Create Table: CREATE TABLE `test_utf8` ( `id` int(11) DEFAULT NULL, `name` varchar(512) DEFAULT NULL, `description` varchar(513) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> alter table test_utf8 engine=MEMORY; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table test_utf8\G *************************** 1. row *************************** Table: test_utf8 Create Table: CREATE TABLE `test_utf8` ( `id` int(11) DEFAULT NULL, `name` varchar(512) DEFAULT NULL, `description` varchar(513) DEFAULT NULL ) ENGINE=MEMORY DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> select * from test_utf8; Field 1: `id` Catalog: `def` Database: `test` Table: `test_utf8` Org_table: `test_utf8` Type: LONG Collation: binary (63) Length: 11 Max_length: 0 Decimals: 0 Flags: NUM Field 2: `name` Catalog: `def` Database: `test` Table: `test_utf8` Org_table: `test_utf8` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 1536 Max_length: 0 Decimals: 0 Flags: Field 3: `description` Catalog: `def` Database: `test` Table: `test_utf8` Org_table: `test_utf8` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 1539 Max_length: 0 Decimals: 0 Flags: 0 rows in set (0.00 sec) So, MEMORY table can store long enough (513 utf8 characters) VARCHAR columns, but, for some reason, temporary table is still created on disk when such column is used in UNION: mysql> show session status like 'cre%'; Field 1: `Variable_name` Catalog: `def` Database: `` Table: `STATUS` Org_table: `` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 192 Max_length: 23 Decimals: 0 Flags: NOT_NULL Field 2: `Value` Catalog: `def` Database: `` Table: `STATUS` Org_table: `` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 3072 Max_length: 2 Decimals: 0 Flags: +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Created_tmp_disk_tables | 2 | | Created_tmp_files | 5 | | Created_tmp_tables | 11 | +-------------------------+-------+ 3 rows in set (0.01 sec) mysql> select description from test_utf8 where id=1 union select description from test_utf8 where id=2; Field 1: `description` Catalog: `def` Database: `` Table: `` Org_table: `` Type: BLOB Collation: utf8_general_ci (33) Length: 4617 Max_length: 0 Decimals: 0 Flags: BLOB 0 rows in set (0.00 sec) mysql> show session status like 'cre%'; Field 1: `Variable_name` Catalog: `def` Database: `` Table: `STATUS` Org_table: `` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 192 Max_length: 23 Decimals: 0 Flags: NOT_NULL Field 2: `Value` Catalog: `def` Database: `` Table: `STATUS` Org_table: `` Type: VAR_STRING Collation: utf8_general_ci (33) Length: 3072 Max_length: 2 Decimals: 0 Flags: +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Created_tmp_disk_tables | 3 | | Created_tmp_files | 5 | | Created_tmp_tables | 12 | +-------------------------+-------+ 3 rows in set (0.00 sec) Why column type is converted to BLOB in the above? It looks like a server bug to me! Especially taking into account the fact that there are no data at all in this case: mysql> explain select description from test_utf8 where id=1 union select description from test_utf8 where id=2; ... +----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables | | 2 | UNION | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables | | NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+ 3 rows in set (0.01 sec)