| Bug #60417 | slow VIEWS by using subselect as column | ||
|---|---|---|---|
| Submitted: | 10 Mar 2011 15:28 | Modified: | 27 Mar 2015 2:54 | 
| Reporter: | Richard Teubel | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Views | Severity: | S4 (Feature request) | 
| Version: | 5.1.51, 5.5.8 | OS: | Any | 
| Assigned to: | CPU Architecture: | Any | |
| Tags: | FUNCTION, slow, subselect, VIEW | ||
   [10 Mar 2011 17:30]
   Valeriy Kravchuk        
  I think the following EXPLAIN results: mysql> explain SELECT ID FROM `ViewWithSubselect`; +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 5 | | | 2 | DERIVED | mytable | ALL | NULL | NULL | NULL | NULL | 5 | | | 3 | SUBQUERY | mytable2 | ALL | NULL | NULL | NULL | NULL | 1 | | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ 3 rows in set (5.04 sec) mysql> explain SELECT ID FROM `ViewWithoutSubselect`; +----+-------------+---------+-------+---------------+-------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+-------+---------+------+------+-------------+ | 1 | SIMPLE | mytable | index | NULL | Group | 5 | NULL | 5 | Using index | +----+-------------+---------+-------+---------------+-------+---------+------+------+-------------+ 1 row in set (0.00 sec) explain the situation. In case of subselect optimizer has to "materialize" the result of select (derived table), and call slow function every time in the process. Without subselect optimizer just access ID from the base table using index and, thus, does not call slow function. Time to execute EXPLAIN shows that this materialization actually happens at optimization stage, not at query execution stage. Optimizer has to use TEMPTABLE algorithm for this view, and this is described in the manual actually (see http://dev.mysql.com/doc/refman/5.5/en/view-algorithms.html): "If the MERGE algorithm cannot be used, a temporary table must be used instead. MERGE cannot be used if the view contains any of the following constructs: - Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth) ... - Subquery in the select list ..." So I think that this is a feature request to process view as MERGE in this case, but not a bug formally.
   [11 Mar 2011 12:08]
   Richard Teubel        
  Thanks for your answer. I change the severity to feature request.
   [11 Mar 2011 12:43]
   Valeriy Kravchuk        
  So, we have a valid feature request here for processing views differently (as MERGE) in case when subselect-based column from the view is NOT really accessed.
   [27 Mar 2015 2:54]
   Paul DuBois        
  Noted in 5.7.7, 5.8.0 changelogs. Previously, derived tables (subqueries) or views in the FROM clause could not be merged into the outer query if they contained subqueries of their own. Instead, they were processed using materialization. This restriction has now been lifted so that queries previously executed using materialization can be executed more quickly using merging.
   [12 Dec 2015 22:21]
   Paul DuBois        
  Revised changelog entry: Previously, derived tables (subqueries) or views in the FROM clause could not be merged into the outer query if they contained subqueries in the SELECT list. Instead, they were processed using materialization. This restriction has now been lifted so that queries previously executed using materialization can be executed more quickly using merging.


Description: Hello, I have a VIEW performance problem if I use a subselect beside slow functions as list of columns. If the subselect in a function then the performanc is ok. In any case the "subselect-column" is not in the VIEW-Query. mysql> SELECT ID -> FROM `ViewWithoutSubselect`; +----+ | ID | +----+ | 1 | .... | 5 | +----+ 5 rows in set (0.00 sec) mysql> SELECT ID -> FROM `ViewWithSubselect`; +----+ | ID | +----+ | 1 | .... | 5 | +----+ 5 rows in set (5.01 sec) <===!! How to repeat: CREATE TABLE IF NOT EXISTS `myTable` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `myGroup` int(11) DEFAULT NULL, `myContent` varchar(20) DEFAULT NULL, `myDate` date DEFAULT NULL, PRIMARY KEY (`ID`), KEY `Group` (`myGroup`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=821 ; INSERT INTO `myTable` (`ID`, `myGroup`, `myContent`, `myDate`) VALUES (1, 2, '+=Z\\X:B|d:mK #5mc', '2011-03-01'), (2, 2, '', '2011-03-01'), (3, 2, 'u/RJI$SJ%T2G+|,e', '2011-03-01'), (4, 2, 'q=7yfy''Ttb:u\\S8h];', '2011-03-01'), (5, 2, '*J5eBaS', '2011-03-01'); CREATE TABLE IF NOT EXISTS `myTable2` ( `Datum` date DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci; INSERT INTO `myTable2` (`Datum`) VALUES ('2011-03-12'); DELIMITER //; CREATE FUNCTION `slowFunction`( pi_ID INTEGER(11) ) RETURNS int(11) DETERMINISTIC READS SQL DATA SQL SECURITY DEFINER COMMENT '' BEGIN Select sleep(1) INTO @testtest; SET @myCount = @myCount+1; RETURN @myCount; END //; CREATE FUNCTION `get_myDate`() RETURNS date DETERMINISTIC READS SQL DATA SQL SECURITY DEFINER COMMENT '' BEGIN DECLARE myDate DATE; SELECT myTable2.`Datum` INTO myDate FROM myTable2 LIMIT 1; RETURN myDate; END//; CREATE SQL SECURITY DEFINER VIEW `ViewWithSubselect` AS select `myTable`.`ID` AS `ID`, `myTable`.`myGroup` AS `myGroup`, `myTable`.`myContent` AS `myContent`, ( select `myTable2`.`Datum` from `myTable2` limit 1) AS `myDate`,`slowFunction`(NULL) AS `SlowFunction` from `myTable`//; CREATE SQL SECURITY DEFINER VIEW `ViewWithoutSubselect` AS select `myTable`.`ID` AS `ID`, `myTable`.`myGroup` AS `myGroup`, `myTable`.`myContent` AS `myContent`, `get_myDate`() AS `myDate`, `slowFunction`(NULL) AS `SlowFunction` from `myTable`//; DELIMITER ; SELECT ID FROM `ViewWithSubselect`; SELECT ID FROM `ViewWithoutSubselect`; show variables like "%version%";