Bug #29582 huge memory consumption with union, subselect, joins

Submitted: 5 Jul 2007 18:57 Modified: 3 Aug 2007 2:29
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S1 (Critical)
Version:5.0.42, 5.0.46BK OS:Any
Assigned to: Sergey Petrunya CPU Architecture:Any
Tags: bfsm_2007_07_19, Leak, Memory, UNION

[5 Jul 2007 18:57] Shane Bester
Description:
A query in this form uses a few hundred MB of ram during execution.
So, for a 32-bit server, you'll be out of memory if two clients execute this at the same time:

I narrowed down the culprit to be the UNION in the derived table.  Without the UNION, the memory doesn't get wasted as much.

The general form of the query is:

SELECT  SQL_CALC_FOUND_ROWS 
        
        COUNT(DISTINCT ...),
        IF(SUM(DISTINCT ...) IS NOT NULL, SUM(DISTINCT ...), 0), 
        IF(... IS NOT NULL, true, false)
FROM
        t1
        INNER JOIN ...
        INNER JOIN ...
        LEFT OUTER JOIN
        (
                SELECT DISTINCT ...
                FROM 
                       ...
                WHERE 
                        ...=5 AND ...=1
        ) ... ON ...
        
WHERE 
(
        ...=true OR 
        ... IS NULL
)  AND 

... IN 
(
        SELECT ....
        FROM
                .....
                INNER JOIN ... ON .....
                INNER JOIN ... ON .....
        WHERE 
                ....=1 AND 
                (..., ...)=(5, 1) AND 
                ...=0 
                
        UNION
        
        SELECT .....
        FROM 
                .....
                INNER JOIN ... ON ......
                INNER JOIN ... ON ......
                INNER JOIN ... ON ...... 
        WHERE 
                ...=2 AND 
                ...=1 AND 
                ...=5
        
)  AND 
...>'2007-02-02 11:09:13.75' 
GROUP BY 
        ....
ORDER BY 
        ... DESC 
LIMIT 20

How to repeat:
simpler testcase will be uploaded later.

Suggested fix:
.
[5 Jul 2007 21:14] Shane Bester
the query above takes 20 seconds on a release build of mysqld, but >10 minutes on a full debug build.  I don't know why that would be..
[18 Jul 2007 15:50] Sergey Petrunya
Ok, the memory consumption is caused by this call:

   mysql_select( various fake_select_lex's members )

this invokes JOIN::optimize which allocates memory on the execution MEM_ROOT. When the union is within the subquery, this causes a total of O(#subselect-executions) memory to be allocated.

The fix seems to be to replace the generic mysql_select() call with 

  if (optimization already done) 
  {
     join->exec();
     // some join->cleanup()-like call here
  }

which is known not to consume memory.
[25 Jul 2007 8:11] Sergey Petrunya
The ETA is 2007-07-27.
[30 Jul 2007 13:13] 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/31817

ChangeSet@1.2532, 2007-07-30 17:12:34+04:00, sergefp@mysql.com +3 -0
  BUG#29582: huge memory consumption with union, subselect, joins:
  - Don't call mysql_select() several times for the select that enumerates
    the temporary table with the results of the UNION. Making this call for
    every subquery execution caused O(#enumerated-rows-in-the-outer-query) 
    memory allocations.
  - Instead, call join->reinit() and join->exec(), and
    = disable constant table detection for such joins,  
    = provide special handling for table-less constant subqueries.
[30 Jul 2007 13:20] 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/31818

ChangeSet@1.2532, 2007-07-30 17:19:49+04:00, sergefp@mysql.com +3 -0
  BUG#29582: huge memory consumption with union, subselect, joins:
  - Don't call mysql_select() several times for the select that enumerates
    the temporary table with the results of the UNION. Making this call for
    every subquery execution caused O(#enumerated-rows-in-the-outer-query) 
    memory allocations.
  - Instead, call join->reinit() and join->exec(), and
    = disable constant table detection for such joins,  
    = provide special handling for table-less constant subqueries.
[31 Jul 2007 11:19] 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/31884

ChangeSet@1.2532, 2007-07-31 15:19:06+04:00, sergefp@mysql.com +3 -0
  BUG#29582: huge memory consumption with union, subselect, joins:
  - Don't call mysql_select() several times for the select that enumerates
    a temporary table with the results of the UNION. Making this call for
    every subquery execution caused O(#enumerated-rows-in-the-outer-query) 
    memory allocations.
  - Instead, call join->reinit() and join->exec(), and
    = disable constant table detection for such joins,  
    = provide special handling for table-less constant subqueries.
[1 Aug 2007 10:15] Sergey Petrunya
Pushed into 5.0-opt at 2007-07-31 13:46:41.
[2 Aug 2007 19:13] Bugs System
Pushed into 5.1.21-beta
[2 Aug 2007 19:15] Bugs System
Pushed into 5.0.48
[3 Aug 2007 2:29] Paul DuBois
Noted in 5.0.48, 5.1.21 changelogs.

Certain statements with unions, subqueries, and joins could
result in huge memory consumption.

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

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