数据库
首页 > 数据库> > 如果我不丢弃它,临时MEMORY表会持续多长时间(MySQL)

如果我不丢弃它,临时MEMORY表会持续多长时间(MySQL)

作者:互联网

我在MySQL中使用递归存储过程来生成一个名为id_list的临时表,但是我必须在后续选择查询中使用该过程的结果,所以我不能在过程中删除临时表…

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 = 0以及它是否运行:

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

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

** N.B.显而易见的答案可能是在提交语句之前删除临时表,但我们暂时假设我不能这样做.*

编辑:为了更准确一点,如果使用持久连接,表将持续多个请求?到目前为止,我们似乎需要明确删除临时表以释放该资源.

更新:基于评论者的建议,我找到了一种调整我的存储过程的方法,以便我可以使用TEMP MEMORY表,但能够在最后显式地删除它…

我没有调用存储过程并使用剩余的TEMP表来收集实际查询中的结果,而是更改了CALL格式以使用第三个OUT变量,如下所示:

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

…然后在存储过程中,我在最后添加了第二个IF层= 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)

瞧!感谢评论员提供的意见,并为我提供了我需要更加努力的理由:)

解决方法:

存储过程中临时表的有趣之处不在于表的暂时存在(在数据库连接终止时丢失),而是存储过程的范围.

有人在StackOverflow:Scope of temp tables created in MySQL stored procedure上问过这个问题.已经有一年多了没有人回答这个问题?让我直截了当地记录下来.事实是:临时表存在于存储过程的内部和外部,但您只能在正在运行的存储过程的范围内使用临时表.

根据the Book

第5章有一个副标题返回结果集到另一个存储过程.

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

Unfortunately, the only way to pass a result set from one stored procedure to another is to pass the results via a temporary table. This is an awkward solution b, and — because the temporary table has scope throughout the entire session — it creates many of the same maintainability issues raised by the use of global variables. but if one stored program needs to supply another stored program with results, then a temporary table can be the best solution.

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

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

更新2014-01-31 11:26 EST

在你的最后评论中,你说

If we employ persistent connections, will the MEMORY table persist through multiple REQUESTS, and it seems it will, so for performance sake, I’m assuming that using this method will *REQUIRE us to explicitly DROP the temporary MEMORY table. Do I assume correctly?

是的和不,我说是的,因为这是一种方法.我说不,因为另一种方法是:

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

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

标签:mysql,memory,stored-procedures,temp-tables
来源: https://codeday.me/bug/20190805/1588766.html