Bug #42948 MySQL Optimizer does not properly use Indexes on Views with "Group By"

Submitted: 17 Feb 2009 23:02 Modified: 3 Mar 2009 18:56
Reporter: John Kounis Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S5 (Performance)
Version:5.0.67-0ubuntu6, 6.0.11 OS:Linux (Ubuntu 8.10)
Assigned to: CPU Architecture:Any
Tags: GROUP BY, Optimizer

[17 Feb 2009 23:02] John Kounis
Description:
If I have a key on a field like SubscriberID and I perform a query such as :

SELECT * FROM qryTEST WHERE SubscriberID=12345;

then it is very fast, since it uses the "SubscriberID" key. However, if I create a view such as:

CREATE VIEW qryTEST AS
SELECT SubscriberID, SUM(Amount) as Total FROM tblTEST GROUP BY SubscriberID;

then it does a table scan, which is very slow.

How to repeat:
Create a test table as follows:

mysql> CREATE TABLE IF NOT EXISTS `tblTEST` (
    ->   `SubscriberID` int(11) NOT NULL,
    ->   `TransactionID` int(11) NOT NULL,
    ->   `Amount` decimal(19,4) NOT NULL,
    ->    PRIMARY KEY  (`TransactionID`),
    ->    KEY (`SubscriberID`));
Query OK, 0 rows affected (0.03 sec)

Insert a bunch of test data (I have a transaction table with over 1 million rows in it:

mysql>
mysql> INSERT INTO tblTEST
    -> SELECT SubscriberID, TransactionID, Amount
    -> FROM tblTransaction;
Query OK, 1245064 rows affected (12.24 sec)
Records: 1245064  Duplicates: 0  Warnings: 0

Create a view:

mysql>
mysql> CREATE VIEW qryTEST AS
    -> SELECT SubscriberID, SUM(Amount) as Total FROM tblTEST GROUP BY SubscriberID;
Query OK, 0 rows affected (0.01 sec)

Test the use of keys:
mysql>
mysql> EXPLAIN SELECT SUM(Amount) FROM tblTEST WHERE SubscriberID=12345;
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-------+
| id | select_type | table   | type | possible_keys | key          | key_len | ref   | rows | Extra |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-------+
|  1 | SIMPLE      | tblTEST | ref  | SubscriberID  | SubscriberID | 4       | const |   25 |       |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql>
mysql> EXPLAIN SELECT * FROM qryTEST WHERE SubscriberID=12345;
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows    | Extra                           |
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL          | NULL | NULL    | NULL |   53228 | Using where                     |
|  2 | DERIVED     | tblTEST    | ALL  | NULL          | NULL | NULL    | NULL | 1245064 | Using temporary; Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
2 rows in set (1.52 sec)
[17 Feb 2009 23:04] John Kounis
Changed severity from S3 to S5 (Performance)
[28 Feb 2009 19:29] Valeriy Kravchuk
Formally, this is not a bug. View is created as follows:

mysql> show create view qryTEST\G
*************************** 1. row ***************************
                View: qrytest
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `qrytest` AS select `tbltest`.`SubscriberID` AS `SubscriberID`,sum(`tbltest`.`Amount`) AS `Total` from `tbltest` group by `tbltest`.`SubscriberID`
character_set_client: latin1
collation_connection: latin1_swedish_ci
1 row in set (0,00 sec)

and as sum() is used server is forced to use emporary table to materialize the view, as explained at http://dev.mysql.com/doc/refman/5.1/en/view-algorithms.html:

mysql> EXPLAIN SELECT * FROM qryTEST WHERE SubscriberID=12345\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 402400
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: tbltest
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 524288
        Extra: Using temporary; Using filesort
2 rows in set (20,09 sec)

It would be nice to remove this limitation one day and push condition down to the SELECT defining view, so this is a reasonable feature request.
[3 Mar 2009 18:56] John Kounis
Thank you for the clarification. I read the link you provided and it's clear why this is happening.

If it would affect the priority of the feature request, perhaps I could give a real-world example that I'm sure is common for database applications:

I have many views to provide information about client transactions that use either aggregate functions or limit functions. A typical monthly invoice run looks something like this:

SELECT CustomerID, <and a bunch of other stuff>
FROM Customers
INNER JOIN qryThisMonthsBalance ON Customer.ID = qryThisMonthsBalance.CustomerID
INNER JOIN qryLastMonthsBalance ON Customer.ID = qryLastMonthsBalance.CustomerID
INNER JOIN qryLastPayment on Customer.ID = qryLastPayment.CustomerID
INNER JOIN qryLastInvoiceSent on Customer.ID = qryLastInvoiceSent.CustomerID
... and so on....

The performance of a query like the one above became unacceptable after converting from MSSQL to MySQL, since each of the views on which I was doing a join was doing a full table scan of 1.2 million records instead of using the "CustomerID" index.

To restore normal performance, I had to write stored procedures to create temporary tables instead of using views as in the example above.

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

Page generated in 0.054 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.