Bug #68072 MySQL 5.1 issue with timediff, group by on multiple columns, join, primary key

Submitted: 12 Jan 2013 18:02 Modified: 13 Jan 2013 15:02
Reporter: Gergely Kutenics Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:5.1, 5.5 OS:Any (Win64, CentOS Linux)
Assigned to: CPU Architecture:Any
Tags: datetime, GROUP BY, GROUP_BY, join, min, SELECT, timediff

[12 Jan 2013 18:02] Gergely Kutenics
Description:
The attached query works as expected on MySQL 5.0 but returns strange results on 5.1 and 5.5.

I tested this on 7 servers including 5.0.96 and 5.1.67 (both are GA available today on mysql.com), and multiple 5.5.x builds. Enabling ONLY_FULL_GROUP_BY does not affect the behavior. The problem comes up with both InnoDB and MyISAM.

I compared the documentation of 5.0 and 5.1 on select, join, primary key, GROUP_BY, min() datetime, and timediff(), and found no information that explains this.

How to repeat:
drop table if exists test_entry_card_events;
create table test_entry_card_events (card_id int not null, event_time datetime not null, event_type enum('entry','exit') not null,
primary key (card_id,event_time,event_type));

insert into test_entry_card_events (card_id,event_time,event_type) values
(4403,'2012.12.04 12:10','entry'),
(4403,'2012.12.05 12:37','entry'),
(4403,'2012.12.05 19:55','exit'),
(4403,'2012.12.06 12:34','entry'),
(4403,'2012.12.06 18:49','exit'),
(4403,'2012.12.20 13:02','entry'),
(4403,'2012.12.20 18:03','exit'),
(4403,'2012.12.21 10:41','entry'),
(4403,'2012.12.21 17:03','exit');

/* unexpected result on MySQL 5.1, 5.5; correct on MySQL 5.0 */
select a.card_id,a.event_time,min(b.event_time),timediff(min(b.event_time),a.event_time) as d
from test_entry_card_events a join test_entry_card_events b on a.card_id=b.card_id and a.event_type='entry' and b.event_type='exit'
and b.event_time>a.event_time group by a.card_id,a.event_time order by a.card_id,a.event_time;

Suggested fix:
I think that MySQL 5.1 (and above) should do what MySQL 5.0 does.

(There are several workarounds: either is to place the join in a nested select query, another is to group by only one column, a third one is to define a primary key that does not include event_type. The problem does not come up when decimal or double data type and subtraction are used in place of datetime and timediff.)
[12 Jan 2013 19:00] Valeriy Kravchuk
This is what I get with 5.5.29 on Windows:

C:\Program Files\MySQL\MySQL Server 5.5\bin>mysql -uroot -proot -P3312 test
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 57
Server version: 5.5.29 MySQL Community Server (GPL)

Copyright (c) 2000, 2012, 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> drop table if exists test_entry_card_events;
Query OK, 0 rows affected, 1 warning (0.53 sec)

mysql> create table test_entry_card_events (card_id int not null, event_time dat
etime not null, event_type enum('entry','exit') not null,
    -> primary key (card_id,event_time,event_type));
Query OK, 0 rows affected (1.92 sec)

mysql> insert into test_entry_card_events (card_id,event_time,event_type) values

    -> (4403,'2012.12.04 12:10','entry'),
    -> (4403,'2012.12.05 12:37','entry'),
    -> (4403,'2012.12.05 19:55','exit'),
    -> (4403,'2012.12.06 12:34','entry'),
    -> (4403,'2012.12.06 18:49','exit'),
    -> (4403,'2012.12.20 13:02','entry'),
    -> (4403,'2012.12.20 18:03','exit'),
    -> (4403,'2012.12.21 10:41','entry'),
    -> (4403,'2012.12.21 17:03','exit');
Query OK, 9 rows affected (0.30 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> select a.card_id,a.event_time,min(b.event_time),timediff(min(b.event_time
),a.event_time) as d
    -> from test_entry_card_events a join test_entry_card_events b on a.card_id=
b.card_id and a.event_type='entry' and b.event_type='exit'
    -> and b.event_time>a.event_time group by a.card_id,a.event_time order by a.
card_id,a.event_time;
+---------+---------------------+---------------------+------------+
| card_id | event_time          | min(b.event_time)   | d          |
+---------+---------------------+---------------------+------------+
|    4403 | 2012-12-04 12:10:00 | 2012-12-05 19:55:00 | 07:18:00   |
|    4403 | 2012-12-05 12:37:00 | 2012-12-05 19:55:00 | -16:39:00  |
|    4403 | 2012-12-06 12:34:00 | 2012-12-06 18:49:00 | -330:13:00 |
|    4403 | 2012-12-20 13:02:00 | 2012-12-20 18:03:00 | -16:38:00  |
|    4403 | 2012-12-21 10:41:00 | 2012-12-21 17:03:00 | 00:00:00   |
+---------+---------------------+---------------------+------------+
5 rows in set (0.25 sec)

The results above look really wrong. Now EXPLAIN:

mysql> explain select a.card_id,a.event_time,min(b.event_time),timediff(min(b.ev
ent_time),a.event_time) as d
    -> from test_entry_card_events a join test_entry_card_events b on a.card_id=
b.card_id and a.event_type='entry' and b.event_type='exit'
    -> and b.event_time>a.event_time group by a.card_id,a.event_time order by a.
card_id,a.event_time\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
         type: index
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 13
          ref: NULL
         rows: 2
        Extra: Using where; Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: test.a.card_id
         rows: 4
        Extra: Using where; Using index
2 rows in set (0.05 sec)

Now, let's just drop primary key:

mysql> alter table test_entry_card_events drop primary key;
Query OK, 9 rows affected (1.06 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> select a.card_id,a.event_time,min(b.event_time),timediff(min(b.event_time
),a.event_time) as d
    -> from test_entry_card_events a join test_entry_card_events b on a.card_id=
b.card_id and a.event_type='entry' and b.event_type='exit'
    -> and b.event_time>a.event_time group by a.card_id,a.event_time order by a.
card_id,a.event_time;
+---------+---------------------+---------------------+----------+
| card_id | event_time          | min(b.event_time)   | d        |
+---------+---------------------+---------------------+----------+
|    4403 | 2012-12-04 12:10:00 | 2012-12-05 19:55:00 | 31:45:00 |
|    4403 | 2012-12-05 12:37:00 | 2012-12-05 19:55:00 | 07:18:00 |
|    4403 | 2012-12-06 12:34:00 | 2012-12-06 18:49:00 | 06:15:00 |
|    4403 | 2012-12-20 13:02:00 | 2012-12-20 18:03:00 | 05:01:00 |
|    4403 | 2012-12-21 10:41:00 | 2012-12-21 17:03:00 | 06:22:00 |
+---------+---------------------+---------------------+----------+
5 rows in set (0.14 sec)

The results above looks correct. But, surely, with index or without, the results should be the same :)
[13 Jan 2013 15:02] Shane Bester
This bug affects 5.1.46 and higher.
5.6 and 5.7 are not affected.
[13 Jan 2013 15:02] Shane Bester
outputs

Attachment: bug68072_versions_test.txt (text/plain), 14.04 KiB.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.040 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.