如果我不刪除它,臨時 MEMORY 表將持續多長時間(MySQL)
我在 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;
呼叫過程時,第一個值是我想要的分支的頂部 ID,第二個值是
tier
過程在遞歸期間使用的。在遞歸循環之前,它會檢查是否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 MEMORY 表,但
DROP
最後能夠顯式地顯示它……我不只是呼叫儲存過程並使用剩餘的 TEMP 表來收集實際查詢中的結果,而是將
CALL
格式更改為使用第三個OUT
變數,如下所示: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)
瞧!感謝評論者的意見,並為我提供了我需要更加努力的理由:)
儲存過程中臨時表的有趣之處與其說是表的暫時存在(在數據庫連接終止時刪除),不如說是儲存過程的範圍。
有人在 StackOverflow 上問過這個問題:在 MySQL 儲存過程中創建的臨時表的範圍。已經一年多了,沒有人回答這個問題?讓我澄清事實。事實是:臨時表存在於儲存過程的內部和外部,但您只能在執行的儲存過程範圍內對臨時表進行操作。
根據書
第 5 章有一個副標題將結果集返回到另一個儲存過程。
它在第 117 頁的第 2 段中說:
不幸的是,將結果集從一個儲存過程傳遞到另一個儲存過程的唯一方法是通過臨時表傳遞結果。這是一個尷尬的解決方案 b,而且——因為臨時表在整個會話中都有範圍——它會產生許多與使用全域變數相同的可維護性問題。但是如果一個儲存程序需要為另一個儲存程序提供結果,那麼臨時表可能是最好的解決方案。
回顧StackOverflow 問題,我可以看到有人從 mysql 客戶端呼叫儲存過程。由於 mysql 客戶端不是儲存過程,因此除了執行 SELECT 以查看結果之外,無法通過 DML 在 mysql 客戶端級別操作結果。由於您呼叫遞歸儲存過程,因此您可以放心,在 DB Connection 期間可以完全訪問臨時表。
我希望這回答了你的問題。
更新 2014-01-31 11:26 EST
在你上一條評論中,你說
如果我們使用持久連接,MEMORY 表是否會通過多個 REQUESTS 持久化,而且似乎會,所以為了性能起見,我假設使用此方法將 *REQUIRE 我們顯式地刪除臨時 MEMORY 表。我假設正確嗎?
是和否。我說是,因為這是一種方法。我說不,因為另一種方法是:
CREATE TEMPORARY TABLE IF NOT EXISTS id_list (iid CHAR(32) NOT NULL) ENGINE=memory; TRUNCATE TABLE id_list;
無論您選擇哪種方式,操作仍然相同,因為 TRUNCATE TABLE 刪除並重新創建表。這不會損害其他數據庫連接,因為每個連接都有自己的 id_list 表。