Bug #26447 "ALTER TABLE .. ORDER" does not work with InnoDB and auto_increment keys
Submitted: 16 Feb 2007 16:45 Modified: 29 Feb 20:03
Reporter: Christian Hammers (Silver Quality Contributor)
Status: Closed
Category:Server Severity:S2 (Serious)
Version:5.0.36-BK, 5.0.30 OS:Any
Assigned to: Ramil Kalimullin Target Version:
Tags: qc
Triage: D2 (Serious)

[16 Feb 2007 16:45] Christian Hammers
Description:
"ALTER TABLE .. ORDER BY .." does not work with InnoDB.
Instead it seems to prefer sorting the table using the varchar column..

bye,

-christian-

How to repeat:
Server version: 5.0.30-Debian_1~bpo.1-log Debian etch distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE TABLE `t` (
    ->   `id` int(11) NOT NULL auto_increment,
    ->   `name` varchar(255) default NULL,
    ->   PRIMARY KEY  (`id`),
    ->   KEY `name` (`name`)
    -> ) ENGINE=innodb;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t VALUES (2,"two"), (-1,"minus one"), (4,"four");
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | four      | 
| -1 | minus one | 
|  2 | two       | 
+----+-----------+
3 rows in set (0.00 sec)

mysql> ALTER TABLE t ORDER BY id;
Query OK, 3 rows affected (0.07 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | four      | 
| -1 | minus one | 
|  2 | two       | 
+----+-----------+
3 rows in set (0.00 sec)

mysql> ALTER TABLE t ENGINE=myisam;
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE t ORDER BY id;
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+-----------+
| id | name      |
+----+-----------+
| -1 | minus one | 
|  2 | two       | 
|  4 | four      | 
+----+-----------+
3 rows in set (0.00 sec)

Suggested fix:
Correct ALTER TABLE.
[16 Feb 2007 17:17] Valeriy Kravchuk
Thank you for a bug report. Verified just as described with latest 5.0.36-BK on Linux:

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.0.36    |
+-----------+
1 row in set (0.01 sec)

mysql> drop table t;
Query OK, 0 rows affected (0.01 sec)

mysql> create table t (
    -> id int auto_increment primary key,
    -> name varchar(255),
    -> key k1(name)) engine=InnoDB;
Query OK, 0 rows affected (0.07 sec)

mysql> INSERT INTO t VALUES (2,'two'), (-1,'minus one'), (4,'four');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> explain select * from t\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: index
possible_keys: NULL
          key: k1
      key_len: 258
          ref: NULL
         rows: 3
        Extra: Using index
1 row in set (0.00 sec)

This is bug #1 here: why k1 index is used? To select ALL ROWS from InnoDB table?

mysql> select * from t;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | four      |
| -1 | minus one |
|  2 | two       |
+----+-----------+
3 rows in set (0.01 sec)

mysql> alter table t order by id;
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> explain select * from t\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: index
possible_keys: NULL
          key: k1
      key_len: 258
          ref: NULL
         rows: 3
        Extra: Using index
1 row in set (0.01 sec)

Same plan, and

mysql> select * from t;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | four      |
| -1 | minus one |
|  2 | two       |
+----+-----------+
3 rows in set (0.00 sec)

same result. I am not sure this is a bug anyway, as nothing in
http://dev.mysql.com/doc/refman/5.0/en/alter-table.html tells you that any specific order
is guaranteed after execution of this statement. But it may worth mentioning that
explicitely. So, let it be bug #2 here.

This is how one may get desired results:

mysql> select * from t ignore index(k1);
+----+-----------+
| id | name      |
+----+-----------+
| -1 | minus one |
|  2 | two       |
|  4 | four      |
+----+-----------+
3 rows in set (0.02 sec)

and:

mysql> explain select * from t ignore index(k1)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 3
        Extra:
1 row in set (0.01 sec)

really shown that when ALL access method is used, rows are really come in "desired" order.
[19 Feb 2007 14:57] Heikki Tuuri
Hi!

This is a docs bug, an SQL optimizer bug, and an SQL interpreter bug.

The fact that SELECT * FROM t does not use the PRIMARY KEY (= clustered index)to retrieve
the rows might be considered an optimizer bug. Using the clustered index for a table scan
is always faster than using a secondary index.

http://dev.mysql.com/doc/refman/5.0/en/alter-table.html

"
ORDER BY enables you to create the new table with the rows in a specific order. Note that
the table does not remain in this order after inserts and deletes. This option is useful
primarily when you know that you are mostly to query the rows in a certain order most of
the time. By using this option after major changes to the table, you might be able to get
higher performance. In some cases, it might make sorting easier for MySQL if the table is
in order by the column that you want to order it by later.
"

The above makes no sense for InnoDB or BDB if there is a user-defined clustered index in
the table.

The MySQL interpreter bug: it should give an error in:

ALTER TABLE ... ORDER BY;

if it is an InnoDB table and there is a PRIMARY KEY or a NOT NULL UNIQUE index in the
table. InnoDB is not aware of the ORDER BY, and cannot give the error.

Regards,

Heikki
[7 Nov 2007 11:28] Ramil Kalimullin
The issue will be fixed in the 5.1 branch.
[7 Nov 2007 17:00] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/37270

ChangeSet@1.2612, 2007-11-07 19:59:58+04:00, ramil@mysql.com +6 -0
  Fix for bug #26447: "ALTER TABLE .. ORDER" does not work with InnoDB 
  and auto_increment keys
  
  Problems: 
    1. ALTER TABLE ... ORDER BY... doesn't make sence if there's a 
       user-defined clustered index in the table.
    2. using a secondary index is slower than using a clustered one 
       for a table scan.
  
  Fixes:
    1. raise a warning.
    2. use the clustered index.
[8 Dec 2007 0:07] Bugs System
Pushed into 6.0.5-alpha
[8 Dec 2007 0:09] Bugs System
Pushed into 5.1.23-rc
[29 Feb 20:03] Paul DuBois
Noted in 5.1.23, 6.0.5 changelogs.

It makes no sense to attempt to use ALTER TABLE ... ORDER BY to order
an InnoDB table if there is a user-defined clustered index, because
rows are always ordered by the clustered index. Such attempts now are
ignored and produce a warning.

Also, in some cases, InnoDB incorrectly used a secondary index when
the clustered index would produce a faster scan. EXPLAIN output now
indicates use of the clustered index (for tables that have one) as
lines with a type value of index, a key value of PRIMARY, and without
Using index in the Extra value.