Bug #62504 "select count(distinct N1), count(distinct N2) from test.AA" works incorrectly
Submitted: 22 Sep 2011 19:44 Modified: 12 Jun 2013 16:30
Reporter: Vyacheslav Brover Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:5.5.15-log, 5.5.17, 5.6.10 OS:Linux
Assigned to: Neeraj Bisht CPU Architecture:Any
Tags: count, distinct, regression, SELECT, unique

[22 Sep 2011 19:44] Vyacheslav Brover
Description:
Incorrect result of a select statement which has more than 1 "count(distinct <Column>)" select expressions.

How to repeat:
create table test.AA (N1 int, N2 int);  /* engine='InnoDB' or engine='MyISAM' */
insert into test.AA (N1, N2) values (1, 1);
insert into test.AA (N1, N2) values (2, 2);

select count(distinct N1), count(distinct N2) from test.AA;
Result: 2 2
Expected: 1 1
[22 Sep 2011 20:04] Vyacheslav Brover
This bug happens when a unique index exists.

How to repeat:

create table test.AA (N1 int, N2 int); /*engine='MyISAM' or engine='InnoDB'*/
create unique index AA_uq on test.AA(N1,N2);
insert into test.AA (N1, N2) values (1, 1);
insert into test.AA (N1, N2) values (1, 2);

select count(distinct N1), count(distinct N2) from test.AA;
-- Result: 2 2
-- Expected: 1 2
[22 Sep 2011 20:42] Vyacheslav Brover
sql_buffer_result may help:
  select sql_buffer_result count(distinct N1), count(distinct N2) from test.AA;  
-- Result: 1 2 (correct)

but 
  select sql_buffer_result T.N1, T.N2 from (select count(distinct N1) N1, count(distinct N2) N2 from test.AA) T;
-- Result: 2 2 (incorrect)
[22 Sep 2011 21:20] MySQL Verification Team
C:\DBS>c:\dbs\5.5\bin\mysql -uroot --port=3540 --prompt="mysql 5.5 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.5.17-log Source distribution

Copyright (c) 2000, 2011, 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 5.5 >use test
Database changed
mysql 5.5 >create table test.AA (N1 int, N2 int); /*engine='MyISAM' or engine='InnoDB'*/
Query OK, 0 rows affected (0.15 sec)

mysql 5.5 >create unique index AA_uq on test.AA(N1,N2);
Query OK, 0 rows affected (0.36 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql 5.5 >insert into test.AA (N1, N2) values (1, 1);
Query OK, 1 row affected (0.09 sec)

mysql 5.5 >insert into test.AA (N1, N2) values (1, 2);
Query OK, 1 row affected (0.09 sec)

mysql 5.5 >
mysql 5.5 >select count(distinct N1), count(distinct N2) from test.AA;
+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  2 |                  2 |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql 5.5 >alter table AA drop index AA_uq;
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql 5.5 >select count(distinct N1), count(distinct N2) from test.AA;
+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  1 |                  2 |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql 5.5 >
[22 Sep 2011 21:25] MySQL Verification Team
Not repeatable with 5.1:

C:\DBS>c:\dbs\5.1\bin\mysql -uroot --port=3510 --prompt="mysql 5.1 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.1.60-Win X64-log Source distribution

Copyright (c) 2000, 2011, 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 5.1 >use test
Database changed
mysql 5.1 >create table test.AA (N1 int, N2 int); /*engine='MyISAM' or engine='InnoDB'*/
Query OK, 0 rows affected (0.05 sec)

mysql 5.1 >create unique index AA_uq on test.AA(N1,N2);
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql 5.1 >insert into test.AA (N1, N2) values (1, 1);
Query OK, 1 row affected (0.01 sec)

mysql 5.1 >insert into test.AA (N1, N2) values (1, 2);
Query OK, 1 row affected (0.00 sec)

mysql 5.1 >
mysql 5.1 >select count(distinct N1), count(distinct N2) from test.AA;
+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  1 |                  2 |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql 5.1 >
[23 Sep 2011 7:47] Valeriy Kravchuk
Thank you for the bug report. Indeed, looks like a regression bug:

macbook-pro:5.5 openxs$ bin/mysql -uroot test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.17-debug Source distribution

Copyright (c) 2000, 2011, 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> create table test.AA (N1 int, N2 int); /*engine='MyISAM' or engine='InnoDB'*/
Query OK, 0 rows affected (0.08 sec)

mysql> create unique index AA_uq on test.AA(N1,N2);
Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into test.AA (N1, N2) values (1, 1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test.AA (N1, N2) values (1, 2);
Query OK, 1 row affected (0.00 sec)

mysql> select count(distinct N1), count(distinct N2) from test.AA;
+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  2 |                  2 |
+--------------------+--------------------+
1 row in set (0.02 sec)

mysql> explain select count(distinct N1), count(distinct N2) from test.AA;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------------------------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra                               |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------------------------------+
|  1 | SIMPLE      | AA    | range | NULL          | AA_uq | 10      | NULL |    3 | Using index for group-by (scanning) |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------------------------------+
1 row in set (0.00 sec)

If we add sql_buffer_result and change the plan:

mysql> select sql_buffer_result count(distinct N1), count(distinct N2) from test.AA;  
+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  1 |                  2 |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql> explain select sql_buffer_result count(distinct N1), count(distinct N2) from test.AA;  
+----+-------------+-------+-------+---------------+-------+---------+------+------+------------------------------------------------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra                                                |
+----+-------------+-------+-------+---------------+-------+---------+------+------+------------------------------------------------------+
|  1 | SIMPLE      | AA    | range | NULL          | AA_uq | 10      | NULL |    3 | Using index for group-by (scanning); Using temporary |
+----+-------------+-------+-------+---------------+-------+---------+------+------+------------------------------------------------------+
1 row in set (0.01 sec)

results are correct. Same without index, as Miguel already pointed out:

mysql> alter table AA drop index AA_uq;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select count(distinct N1), count(distinct N2) from test.AA;+--------------------+--------------------+
| count(distinct N1) | count(distinct N2) |
+--------------------+--------------------+
|                  1 |                  2 |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql> explain select count(distinct N1), count(distinct N2) from test.AA;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | AA    | ALL  | NULL          | NULL | NULL    | NULL |    2 |       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.01 sec)

So, we have a clear bug here.
[29 Sep 2011 21:11] Vyacheslav Brover
OS is Linux.
[16 Feb 2012 4:20] Valeriy Kravchuk
Bug #64343 was marked as a duplicate of this one.
[3 Jul 2012 15:09] Daniel DeLorme
I've also run across this bug; in my case the unique index had a third column, and I noticed that the result of count distinct was the number of distinct rows for the first two columns. In other words,
  SELECT COUNT(DISTINCT a), COUNT(DISTINCT b)
was equivalent to
  SELECT COUNT(DISTINCT a,b), COUNT(DISTINCT a,b)
[19 Mar 2013 11:43] MySQL Verification Team
Bug #68716 was marked as a duplicate of this one.
[19 Mar 2013 18:09] MySQL Verification Team
As reporter mentioned in #68716 - is similar of Bug #62504 but adding sql_buffer_result the result is the same.

I think that Bug #68716 and  Bug #62504 are duplicates and not separate bugs
because sql_buffer_result is not 100% reliable workaround in 62504 too.

#####

mysql> create table AA (N1 int, N2 int, PRIMARY KEY (N1), KEY (N2));
Query OK, 0 rows affected (0.08 sec)

mysql> insert into AA (N1, N2) values (1, 1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into AA (N1, N2) values (2, 1);
Query OK, 1 row affected (0.02 sec)

mysql> SELECT count(distinct (N1)), count(distinct (N2)) FROM AA;
+----------------------+----------------------+
| count(distinct (N1)) | count(distinct (N2)) |
+----------------------+----------------------+
|                    2 |                    2 |
+----------------------+----------------------+
1 row in set (0.01 sec)

mysql> SELECT sql_buffer_result count(distinct (N1)), count(distinct (N2)) FROM AA;
+----------------------+----------------------+
| count(distinct (N1)) | count(distinct (N2)) |
+----------------------+----------------------+
|                    2 |                    2 |
+----------------------+----------------------+
1 row in set (0.01 sec)

mysql> select version();
+------------------+
| version()        |
+------------------+
| 5.6.10-debug-log |
+------------------+
1 row in set (0.00 sec)

##########

[root@ushastry mysql-5.5.31]# bin/mysql -u root -p -S /tmp/5531_/sock 
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.31-debug Source distribution

Copyright (c) 2000, 2013, 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 table AA (N1 int, N2 int, PRIMARY KEY (N1), KEY (N2));
Query OK, 0 rows affected (0.08 sec)

mysql> insert into AA (N1, N2) values (1, 1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into AA (N1, N2) values (2, 1);
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> SELECT count(distinct (N1)), count(distinct (N2)) FROM AA;
+----------------------+----------------------+
| count(distinct (N1)) | count(distinct (N2)) |
+----------------------+----------------------+
|                    2 |                    1 |
+----------------------+----------------------+
1 row in set (0.03 sec)
[12 Jun 2013 16:30] Erlend Dahl
[10 Jun 2013 11:21] Paul Dubois

Noted in 5.5.33, 5.6.13, 5.7.2 changelogs.

Incorrect results could be returned from queries that used several
aggr_func(DISTINCT) functions (where aggr_func is an aggregate
function such as COUNT()) when these referred to different columns of
the same composite key.