ouc*_*cil 13 mysql stored-procedures memory temporary-tables
我在 MySQL 中使用递归存储过程来生成一个名为 的临时表id_list,但我必须在后续选择查询中使用该过程的结果,所以我不能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;
Run Code Online (Sandbox Code Playgroud)
调用过程时,第一个值是我想要的分支的顶部 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;
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:如果我在程序结束时或在我的事务中没有DROP临时MEMORY表,该表将在内存中保留多长时间?会话结束后它会自动删除,还是只要连接打开它就会保留在内存中?
**注意,显而易见的答案可能是在提交语句之前删除临时表,但让我们暂时假设我不能这样做。*
编辑:更准确地说,如果使用持久连接怎么办,该表是否会通过多个请求持续存在?到目前为止,它似乎会并且我们需要明确删除临时表以释放该资源。
更新:根据评论者的建议,我找到了一种调整存储过程的方法,以便我可以利用 TEMP MEMORY 表,但最后能够明确地使用DROP它...
我不仅调用存储过程并使用剩余的 TEMP 表来收集实际查询中的结果,还更改了CALL格式以使用第三个OUT变量,如下所示:
CALL fetch_inheritance_groups('abc123','0',@IDS);
Run Code Online (Sandbox Code Playgroud)
...然后在存储过程中,我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;
Run Code Online (Sandbox Code Playgroud)
因此,存储过程的结果现在是与 兼容的逗号分隔的 ID 列表FIND_IN_SET,因此修改了最终查询,以便:
WHERE r.Group_ID = 'abc123' OR r.Group_ID IN (SELECT * FROM id_list)
Run Code Online (Sandbox Code Playgroud)
... 就是现在 ...
WHERE r.Group_ID = 'abc123' OR FIND_IN_SET(r.Group_ID,@IDS)
Run Code Online (Sandbox Code Playgroud)
瞧!感谢评论员的意见,并给了我需要努力尝试的理由:)
Rol*_*DBA 17
存储过程中临时表的有趣之处与其说是表的暂时存在(在数据库连接终止时被删除),不如说是存储过程的范围。
有人在 StackOverflow 上问了这个问题:在 MySQL 存储过程中创建的临时表的范围。一年多了没人回答这个问题?让我记录一下。事实是:临时表存在于存储过程的内部和外部,但您只能在正在运行的存储过程的范围内使用临时表执行操作。
根据书

第 5 章有一个副标题将结果集返回到另一个存储过程。
它在第 117 页的第 2 段中说:
不幸的是,将结果集从一个存储过程传递到另一个存储过程的唯一方法是通过临时表传递结果。这是一个笨拙的解决方案 b,并且——因为临时表具有贯穿整个会话的范围——它产生了许多由使用全局变量引起的相同的可维护性问题。但是如果一个存储程序需要为另一个存储程序提供结果,那么临时表可能是最好的解决方案。
回顾StackOverflow 问题,我可以看到有人从 mysql 客户端调用了存储过程。由于 mysql 客户端不是存储过程,因此除了执行 SELECT 以查看结果之外,无法通过 DML 操作 mysql 客户端级别的结果。由于您调用了递归存储过程,因此您可以放心,在 DB Connection 期间可以完全访问临时表。
我希望这回答了你的问题。
在您的上一条评论中,您说
如果我们使用持久连接,MEMORY 表是否会通过多个 REQUESTS 持续存在,而且似乎会如此,因此为了性能起见,我假设使用这种方法将 *REQUIRE 我们明确地删除临时 MEMORY 表。我假设正确吗?
是和否。我说是,因为这是一种方法。我说不,因为另一种方法是:
CREATE TEMPORARY TABLE IF NOT EXISTS id_list (iid CHAR(32) NOT NULL) ENGINE=memory;
TRUNCATE TABLE id_list;
Run Code Online (Sandbox Code Playgroud)
无论您选择哪种方式,操作仍然相同,因为 TRUNCATE TABLE 删除并重新创建表。这不会损害其他数据库连接,因为每个连接都有自己的 id_list 表。
| 归档时间: |
|
| 查看次数: |
51909 次 |
| 最近记录: |