如果我不删除临时内存表,该表将保留多长时间(MySQL)


13

我在MySQL中使用递归存储过程来生成名为的临时表id_list,但我必须在后续的select查询中使用该过程的结果,因此无法DROP在该过程中使用该临时表...

BEGIN;

/* generates the temporary table of ID's */
CALL fetch_inheritance_groups('abc123',0);

/* uses the results of the stored procedure in the WHERE */
SELECT a.User_ID
FROM usr_relationships r 
INNER JOIN usr_accts a ON a.User_ID = r.User_ID 
WHERE r.Group_ID = 'abc123' OR r.Group_ID IN (SELECT * FROM id_list) 
GROUP BY r.User_ID;

COMMIT;

调用该过程时,第一个值是我想要的分支的最高ID,第二个值是tier该过程在递归过程中使用的ID 。在递归循环之前,它会检查是否tier = 0运行:

DROP TEMPORARY TABLE IF EXISTS id_list;
CREATE TEMPORARY TABLE IF NOT EXISTS id_list (iid CHAR(32) NOT NULL) ENGINE=memory;

所以我的问题是:如果在过程结束时或事务中没有DROP临时MEMORY表,那么该表将在内存中保留多长时间?会话结束后会自动删除它吗,还是只要连接打开就将它保留在内存中?

** NB显而易见的答案可能是在提交语句之前删除临时表,但让我暂时假设我做不到。*


编辑:更精确一点,如果使用持久连接怎么办,该表将通过多个请求持久化吗?到目前为止,看来并且我们将需要显式删除temp表以释放该资源。


更新:根据评论者的建议,我找到了一种调整存储过程的方法,这样我可以利用TEMP MEMORY表,但最后可以显式地DROP...

我改变了CALL格式以使用第三个OUT变量,而不仅仅是调用存储过程并使用剩余的TEMP表在实际查询中收集结果,而是这样:

CALL fetch_inheritance_groups('abc123','0',@IDS);

...然后在存储过程中,我IF tier = 0在末尾添加了以下内容:

IF tier = 0
    THEN
    SELECT GROUP_CONCAT(DISTINCT iid SEPARATOR ',') FROM id_list INTO inherited_set;
    DROP TEMPORARY TABLE IF EXISTS id_list;
END IF;

因此,存储过程的结果现在是与兼容的ID的逗号分隔列表FIND_IN_SET,因此最终查询被修改为:

WHERE r.Group_ID = 'abc123' OR r.Group_ID IN (SELECT * FROM id_list)

... 就是现在 ...

WHERE r.Group_ID = 'abc123' OR FIND_IN_SET(r.Group_ID,@IDS)

瞧!感谢评论员的输入,并感谢我给我加倍努力的理由:)

Answers:


17

对于存储过程中的临时表,有趣的不是表的瞬时存在(在数据库连接终止时会被删除),而是存储过程的范围。

有人在StackOverflow上问了这个问题:在MySQL存储过程中创建的临时表的范围。已经一年多了,没人回答这个问题?让我保持纪录。事实是:临时表存在于存储过程的内部和外部,但是临时表只能在正在运行的存储过程的范围内进行操作

根据

kdsjx

第5章有一个小标题,将结果集返回到另一个存储过程

它在第117页的第2段中说:

不幸的是,将结果集从一个存储过程传递到另一个存储过程的唯一方法是通过临时表传递结果。这是一个尴尬的解决方案b,并且由于临时表在整个会话中都具有作用域,因此它会产生许多由于使用全局变量而引起的可维护性问题。但是,如果一个存储程序需要向另一个存储程序提供结果,那么临时表可能是最好的解决方案。

回顾StackOverflow问题,我可以从mysql客户端看到有人称为存储过程。由于mysql客户端不是存储过程,因此除了通过SELECT查看结果以外,无法通过DML在mysql客户端级别上操纵结果。由于调用了递归存储过程,因此可以放心,在数据库连接期间,临时表可以完全访问

我希望这回答了你的问题。

更新2014-01-31 11:26 EST

在您最后的评论中,您说

如果我们使用持久性连接,则MEMORY表将通过多个REQUESTS持久化,而且看来它将如此,因此,出于性能考虑,我假设使用此方法将*要求我们显式删除临时MEMORY表。我假设正确吗?

是和否。我说是,因为这是一种方法。我说不,因为另一种方法是:

CREATE TEMPORARY TABLE IF NOT EXISTS id_list (iid CHAR(32) NOT NULL) ENGINE=memory;
TRUNCATE TABLE id_list;

无论选择哪种方式,由于TRUNCATE TABLE都会删除并重新创建表,因此操作仍然相同。这不会损害其他数据库连接,因为每个连接都有自己的id_list表。


非常感谢Rolando!我在SO上发布了相同的问题(stackoverflow.com/questions/21483448/…),以防万一它引起更多关注,并且我也得到了类似的答案,尽管信息量较少。我提出了一个后续措施:如果我们使用持久连接,那么MEMORY表是否会通过多个REQUESTS持久化,而且看来如此,因此出于性能方面的考虑,我假设使用此方法*要求我们显式地DROP使用临时MEMORY表。我假设正确吗?
oucil 2014年

关于您的UPDATE,我想我更关心的是将不再需要的资源留在原处,直到再次运行该查询为止,而且我认为无论是否我不应该显式删除它,这一点变得越来越明显。不需要。
oucil 2014年

不幸的是,将结果集从一个存储过程传递到另一个存储过程的唯一方法是通过一个临时表传递结果。这是否意味着仅当我们知道在被调用过程中创建的临时表的名称时,才能访问结果集(从调用方)?不是像读取SELECT存储过程(DECLARE aCursor CURSOR FOR SELECT ...)中的语句结果集那样使用读取结果集的方法吗?例如 DECLARE theCursor CURSOR FOR CALL aProcedure()
Mir-Ismaili

2

在大多数DBMS中,除非另有说明或除非有明确的事务回滚,否则临时表将一直保留到当前连接结束(在某些系统中,回滚仅会影响表的内容,如果需要,可以重新填充对象本身) 。该表(默认情况下)将对其他连接不可见,无论创建该表的连接持续多长时间。

在Google上进行的快速扫描似乎表明这是mySQL的运行方式。
http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm指出“默认情况下,当数据库连接终止时,MySQL将删除所有临时表”)

但是,通常有多种方法可以更改这些行为。例如,在MS SQL Server中,您可以创建一个临时表,该表对所有连接可见,而不仅仅是当前连接,只需为其指定一个以##开头的名称即可。

我总是在不再需要临时表时将它们丢弃,以免造成混乱。在连接池导致临时表创建导致错误之前,我已经被人咬伤了,因为同名的临时表已经创建但在使用当前连接的先前操作中没有被破坏。


我同意我应该找到一种显式删除表的方法,但是通过DROP在初始层的IF中重新创建之前使用before可以解决您遇到的问题。感谢您的输入!
2014年

-2
CREATE TEMPORARY TABLE  IF NOT EXISTS temp (Months VARCHAR(50),Sequence INT)
AS (
SELECT 
CONCAT(MONTHNAME(m1),' ',YEAR(m1)) AS Months,CONVERT(m1,DATE) AS Sequence
FROM
(
SELECT 
('2014-01-01' - INTERVAL DAYOFMONTH('2014-01-01')-1 DAY) 
+INTERVAL m MONTH AS m1
FROM
(
SELECT @rownum:=@rownum+1 AS m FROM
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t2,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t3,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t4,
(SELECT @rownum:=-1) t0
) d1
) d2 
WHERE m1<= '2015-07-30'
ORDER BY m1
) ;

SELECT t.Months,A.OpenCount,A.CloseCount FROM Temp T
 LEFT JOIN ( SELECT  CONCAT(MONTHNAME(e.dtcdate),' ',YEAR(e.dtcdate)) AS Months,
 ( SELECT  COUNT(csr.ddlcsstatus) FROM csrcrn_frmempengagreqs csr 
 JOIN master_detail md ON md.masterDetailId=csr.ddlcsstatus WHERE md.abbr='open' AND csr.dtcdate >='2014-01-01' AND csr.dtcdate <='2015-07-30' AND csr.ddlArea=e.ddlArea ) AS OpenCount
 ,
 ( SELECT  COUNT(csr.ddlcsstatus) FROM csrcrn_frmempengagreqs csr 
 JOIN master_detail md ON md.masterDetailId=csr.ddlcsstatus WHERE md.abbr='Close' AND csr.dtcdate >='2014-01-01' AND csr.dtcdate <='2015-07-30' AND csr.ddlArea=e.ddlArea ) AS CloseCount

 FROM csrcrn_frmempengagreqs e 
 INNER JOIN master_detail m ON e.ddlcsstatus=m.masterDetailId 
  WHERE  e.dtcdate >='2014-01-01' AND e.dtcdate <='2015-07-30' 
 GROUP BY MONTH(e.dtcdate) ORDER BY e.dtcdate 
 ) A ON CONVERT(A.Months,CHAR(20))=CONVERT(T.Months,CHAR(20)) 
       ORDER BY T.Sequence; 
       DROP TEMPORARY TABLE  IF EXISTS temp;

/ *给定查询成功给出结果...当将此查询放入USP时,显示错误plz帮助我..proc在下面给出* /

DELIMITER $$

DROP PROCEDURE IF EXISTS `usp_GetEngMonthlyChart_Test`$$

CREATE DEFINER=`root`@`%` PROCEDURE `usp_GetEngMonthlyChart_Test`(IN DateFrom DATE,IN DateTo DATE)
BEGIN
      -- SET @strWhere= CONCAT(' AND CSR.dtcInductionDate BETWEEN ''',CONVERT(DateFrom,DATE),''' AND ','''',CONVERT(DateTo,DATE),''''); 


    SET @strSql=CONCAT(' 

    CREATE TEMPORARY TABLE  IF NOT EXISTS temp (Months VARCHAR(50),Sequence INT)
    AS (
    SELECT 
    CONCAT(MONTHNAME(m1),'' '',YEAR(m1)) AS Months,CONVERT(m1,DATE) AS Sequence
    FROM
    (
    SELECT 
    (''',DateFrom,''' - INTERVAL DAYOFMONTH(''',DateFrom,''')-1 DAY) 
    +INTERVAL m MONTH AS m1
    FROM
    (
    SELECT @rownum:=@rownum+1 AS m FROM
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t1,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t2,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t3,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t4,
    (SELECT @rownum:=-1) t0
    ) d1
    ) d2 
    WHERE m1<= ''',DateTo,'''
    ORDER BY m1
    )' );   

         SET @strSql=CONCAT(@strSql,'; GO SELECT t.Months,A.OpenCount,A.CloseCount FROM Temp T
     LEFT JOIN ( SELECT  CONCAT(MONTHNAME(e.dtcdate),'' '',YEAR(e.dtcdate)) AS Months,
     ( SELECT  COUNT(csr.ddlcsstatus) FROM csrcrn_frmempengagreqs csr 
     JOIN master_detail md ON md.masterDetailId=csr.ddlcsstatus WHERE md.abbr=''open'' AND csr.dtcdate >=''',DateFrom,
     ''' AND csr.dtcdate <=''',DateTo,''' AND csr.ddlArea=e.ddlArea ) AS OpenCount
     ,
     ( SELECT  COUNT(csr.ddlcsstatus) FROM csrcrn_frmempengagreqs csr 
     JOIN master_detail md ON md.masterDetailId=csr.ddlcsstatus WHERE md.abbr=''Close'' AND csr.dtcdate >=''',DateFrom,
     ''' AND csr.dtcdate <=''',DateTo,''' AND csr.ddlArea=e.ddlArea ) AS CloseCount

     FROM csrcrn_frmempengagreqs e 
     INNER JOIN master_detail m ON e.ddlcsstatus=m.masterDetailId 
      WHERE  e.dtcdate >=''',DateFrom,''' AND e.dtcdate <=''',DateTo,''' 
     GROUP BY MONTH(e.dtcdate) ORDER BY e.dtcdate 
     ) A ON CONVERT(A.Months,CHAR(20))=CONVERT(T.Months,CHAR(20)) 
           ORDER BY T.Sequence; 
           DROP TEMPORARY TABLE  IF EXISTS temp;'); 

    SELECT @strSql;
    PREPARE stmt FROM @strSql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END$$

DELIMITER ;

致电usp_GetEngMonthlyChart_Test('2014-01-01','2015-07-30')


2
仅仅发布代码是不够的。这需要一个解释
James Anderson
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.