Bug #68350 query proc - re-execute of stored routine, inefficient query plan
Submitted: 12 Feb 2013 14:00 Modified: 29 May 2013 17:30
Reporter: Aleks Pol Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S1 (Critical)
Version:5.6.11 OS:Any (7)
Assigned to: CPU Architecture:Any
Tags: query proc

[12 Feb 2013 14:00] Aleks Pol
Description:
first time 
call rozklad(2012)       time 0.81 sec

second time 
call rozklad(2012)       time 1 min 51 sec

next time 
call rozklad(2012)       time 1 min 51 sec

How to repeat:
DELIMITER $$

USE `dekanat`$$

DROP PROCEDURE IF EXISTS `rozklad`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `rozklad`(IN iRik YEAR)
BEGIN
SELECT
      trozklad.ID 
    ,  trozpodil.Ses AS piv 
    , tpredmets.GroupID
    , tpredmets.Name AS Predmet
    , tgroups.Name AS Grupa
    ,  CONCAT(tlogin.FName,' ', SUBSTR(tlogin.Name,1,1),'. ', SUBSTR(tlogin.LName,1,1),'.') AS FIO
    , trozklad.T
    ,  CASE trozklad.Type   WHEN 1 THEN 'Лек' WHEN 2 THEN 'Пр' WHEN 3 THEN 'Лаб' END AS TYPE
    , trozklad.Ses
    , trozklad.God
    , trozklad.Den
    , trozklad.Para
    , trozklad.Podgrupa
    , tfakultet.Name  AS Fakultet
    ,  tnkp.Name AS NKP
    , tfnavch.Name AS FNavch
    , tkafedra.Name AS Kafedra
    , tgroups.Kurs
    , IF(trozklad.Type=1,tpredmets.PotokID,NULL) AS PotokID
    , IF(trozklad.Type=2,tpredmets.PotokPrID,NULL) AS PotokPrID
    , IF(trozklad.Type=3,tpredmets.PotokLabID,NULL) AS PotokLabID
    , trozklad.Vichitano
    , a.PotokLec
    , a1.PotokPr
    , a2.PotokLab
 #  ,tpredmets.KafedraID
    , a3.Posada
FROM
  trozklad
    INNER JOIN trozpodil ON (trozklad.RozpodilID = trozpodil.ID)
    INNER JOIN tpredmetsinfo ON (trozpodil.PredmetsInfoID = tpredmetsinfo.ID)
    INNER JOIN tlogin ON (tpredmetsinfo.LoginID = tlogin.ID)
    INNER JOIN tpredmets ON (tpredmetsinfo.PredmetsID = tpredmets.ID)
    INNER JOIN tkafedra ON (tpredmets.KafedraID = tkafedra.ID)
    INNER JOIN tgroups ON (tpredmets.GroupID = tgroups.ID)
    INNER JOIN tfnavch ON (tgroups.FnavchID = tfnavch.ID)
    INNER JOIN tfakultet ON (tgroups.FakultetId = tfakultet.ID) 
    LEFT JOIN tnkp ON (tgroups.NkpID=tnkp.ID)
LEFT JOIN 
(SELECT GROUP_CONCAT( tgroups.Name) AS PotokLec,tpredmets.PotokID  FROM tpredmets 
INNER JOIN tgroups ON (tpredmets.GroupID = tgroups.ID)
WHERE tpredmets.PotokID IS NOT NULL
GROUP BY tpredmets.PotokID  
) AS a ON (tpredmets.PotokID=a.potokid) AND (trozklad.Type=1)
LEFT JOIN 
(SELECT GROUP_CONCAT( tgroups.Name) AS PotokPr,tpredmets.PotokPrID  FROM tpredmets 
INNER JOIN tgroups ON (tpredmets.GroupID = tgroups.ID)
WHERE tpredmets.PotokPrID IS NOT NULL
GROUP BY tpredmets.PotokPrID  
) AS a1 ON (tpredmets.PotokPrID=a1.potokPrid) AND (trozklad.Type=2)   
LEFT JOIN 
(SELECT GROUP_CONCAT( tgroups.Name) AS PotokLab,tpredmets.PotokLabID  FROM tpredmets 
INNER JOIN tgroups ON (tpredmets.GroupID = tgroups.ID)
WHERE tpredmets.PotokLabID IS NOT NULL
GROUP BY tpredmets.PotokLabID  
) AS a2 ON (tpredmets.PotokLabID=a2.potokLabid) AND (trozklad.Type=3)  
LEFT JOIN 
(
SELECT
    CONCAT(IFNULL(tposada.Name,''),' - ',IFNULL(tposada.Stupin,'')) AS Posada
    ,tposadainfo.kafedraid
    ,tposadainfo.loginid
FROM
     tposadainfo 
    LEFT JOIN tposada 
        ON (tposadainfo.PosadaID = tposada.ID)
GROUP BY tposadainfo.kafedraid
    ,tposadainfo.loginid
) AS a3 ON (tpredmets.kafedraid=a3.kafedraid  AND tpredmetsinfo.loginid=a3.loginid  )
WHERE tgroups.Rik=iRik AND trozpodil.noRoz=0
ORDER BY  piv, trozklad.T,  tgroups.Name,trozklad.Den  , trozklad.Para ;           
END$$

DELIMITER ;
[13 Feb 2013 13:48] Shane Bester
Hi Alex,

Please help us to narrow down the cause.  Please send us the schema?

mysqldump --no-defaults -uroot -p --all-databases --no-data --routines > out.sql
[16 Feb 2013 12:35] Shane Bester
Hi Aleks,  I made what I believe to be a simple testcase.  Please, check it.

-------------
drop table if exists `t1`;
create table `t1`(`a` int,key(`a`))engine=innodb;
insert into `t1` values (1),(2),(3),(4),(5),(6),(7);
insert into `t1` select `t1`.`a` from `t1`,`t1` `t2`,
`t1` `t3`,`t1` `t4`,`t1` `t5`;
drop procedure if exists `p1`;

create procedure `p1`() 
select count(*) from `t1` 
left join (select `a` from `t1`) `z` on `z`.`a`=`t1`.`a`;

call `p1`();
call `p1`();
call `p1`();

flush tables;

call `p1`();
call `p1`();
call `p1`();

-------------

I got execution times:

mysql> call `p1`();
+----------+
| count(*) |
+----------+
| 40387228 |
+----------+
1 row in set (2.15 sec)

Query OK, 0 rows affected (2.15 sec)

mysql> call `p1`();
+----------+
| count(*) |
+----------+
| 40387228 |
+----------+
1 row in set (13.00 sec)

Query OK, 0 rows affected (13.00 sec)

mysql> call `p1`();
+----------+
| count(*) |
+----------+
| 40387228 |
+----------+
1 row in set (12.98 sec)

Query OK, 0 rows affected (12.98 sec)
---------------------
[16 Feb 2013 13:00] Shane Bester
Here is a testcase that is more dramatic.

drop table if exists `t1`;
create table `t1`(`a` int,key(`a`))engine=innodb;
set @a:=9;
insert into `t1` values (1),(2),(3),(4),(5),(6),(7),(8),(9);
insert into `t1` select @a:=@a+1 from `t1`,`t1` `t2`,
`t1` `t3`,`t1` `t4`,`t1` `t5`;
drop procedure if exists `p1`;
create procedure `p1`() 
select count(*) from `t1` left join (select `a` from `t1`) `z` on `z`.`a`=`t1`.`a`;
call `p1`();  #1 row in set (0.08 sec)
call `p1`();  #1 row in set (2 min 21.71 sec)
[19 Apr 2013 7:17] Aleks Pol
баг остался
[29 May 2013 17:30] Paul Dubois
Noted in 5.6.12, 5.7.2 changelogs.

Indexed on derived tables that were used during the first invocation
of a stored procedure were not used in subsequent invocations.