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で、2番目の値はプロシージャが再帰中に使用する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
しない場合、そのテーブルはメモリ内にどのくらい持続しますか?セッションが終了すると自動的に削除されますか、それとも接続が開いている限りメモリに残りますか?
** N.B。明白な答えは、コミットステートメントの前に一時テーブルを削除することかもしれませんが、一瞬、私がそれを実行できないと仮定しましょう。*
[〜#〜] edit [〜#〜]:もう少し正確に言うと、永続的な接続が採用されている場合、テーブルは複数のリクエストを通じて永続化されますか?これまでのところ、そうであり、一時テーブルを明示的に削除してそのリソースを解放する必要があるようです。
[〜#〜] update [〜#〜]:コメント投稿者のアドバイスに基づいて、TEMP MEMORYテーブルを利用できるようにストアドプロシージャを調整する方法を見つけましたが、最後に明示的にDROP
できます...
ストアドプロシージャを呼び出して残りのTEMPテーブルを使用して実際のクエリの結果を収集するのではなく、CALL
形式を変更して、3番目のOUT
変数を次のように使用します。
CALL fetch_inheritance_groups('abc123','0',@IDS);
...次に、ストアドプロシージャ内で、最後に2番目の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;
したがって、ストアドプロシージャの結果は、FIND_IN_SET
と互換性のあるIDのコンマ区切りのリストになり、最終的なクエリは次のように変更されました。
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)
出来上がり!あなたの入力、および私が少し頑張る必要がある理由を私に与えてくれたコメント投稿者に感謝します:)
ストアドプロシージャの一時テーブルの面白い点は、テーブルの一時的な存在(DB接続の終了時に削除される)ではなく、ストアドプロシージャのスコープです。
StackOverflowで誰かがこの質問をしました: MySQLストアドプロシージャで作成された一時テーブルのスコープ 。 1年以上が経過し、誰も質問に答えていませんか?記録を正直にさせてください。事実は次のとおりです。一時テーブルはストアドプロシージャの内部と外部に存在しますが、一時テーブルで実行できるのは、実行中のストアドプロシージャのスコープ内のみです。 。
The Book によると
第5章には小見出しがあり、結果セットを別のストアドプロシージャに返す。
それは117ページのパラグラフ2で言う:
残念ながら、あるストアドプロシージャから別のストアドプロシージャに結果セットを渡す唯一の方法は、一時テーブルを介して結果を渡すことです。これは厄介なソリューションbであり、一時テーブルにはセッション全体にわたってスコープがあるため、グローバル変数の使用によって引き起こされる同じ保守性の問題の多くが作成されます。ただし、あるストアドプログラムが別のストアドプログラムに結果を提供する必要がある場合、一時テーブルが最善の解決策になる可能性があります。
StackOverflowの質問 を振り返ると、mysqlクライアントからストアドプロシージャと呼ばれる人がいます。 mysqlクライアントはストアドプロシージャではないため、結果を表示するためにSELECTを実行する以外に、DMLを介してmysqlクライアントレベルを操作することはできません。 再帰的なストアドプロシージャを呼び出すので、DB接続の間、一時テーブルに完全にアクセスできるため、安心できます。
これがあなたの質問に答えてくれることを願っています。
あなたの最後のコメントで、あなたは言った
永続的な接続を使用する場合、MEMORYテーブルは複数のREQUESTSを通じて永続化しますが、永続化するように思われるため、パフォーマンス上の理由から、このメソッドを使用すると一時的なMEMORYテーブルを明示的に削除する必要があると想定しています。私は正しく仮定しますか?
はい、いいえ。それを行う1つの方法であるため、私は「はい」と言います。それを行う別の方法があるので、私はノーと言います:
CREATE TEMPORARY TABLE IF NOT EXISTS id_list (iid CHAR(32) NOT NULL) ENGINE=memory;
TRUNCATE TABLE id_list;
どちらの方法を選択しても、TRUNCATE TABLEがテーブルを削除して再作成するため、操作は同じです。各接続には独自のid_listテーブルがあるため、これは他のDB接続に悪影響を与えません。
ほとんどのDBMSでは、特に指定されていない限り、または明示的なトランザクションロールバックがない限り、一時テーブルは現在の接続が終了するまで存続します(一部のシステムでは、ロールバックはテーブルのコンテンツにのみ影響し、必要に応じてオブジェクト自体を再配置する場合があります)。 。テーブルは、デフォルトでは、それを作成する接続がどれほど長く続くかに関係なく、他の接続からは見えません。
Googleでのクイックスキャンは、これがmySQLの動作方法であることを示しているようです。
( http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm は、「デフォルトでは、データベース接続が終了すると、MySQLによってすべての一時テーブルが削除される」と記載されています)
ただし、多くの場合、これらの動作を変更する方法があります。たとえば、MS SQL Serverでは、##で始まる名前を付けることで、現在の接続だけでなく、すべての接続に表示される一時テーブルを作成できます。
混乱を避けるために、一時テーブルが不要になったらすぐに削除します。同じ名前の一時テーブルが作成されたが、現在の接続を使用する以前のアクションで破棄されなかったため、接続プーリングが一時テーブルの作成でエラーを引き起こす原因になったことがありました。