一時的なMEMORYテーブルを削除しない場合、どのくらい持続しますか(MySQL)


13

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;

したがって、私の質問は次のとおりです。手順の最後またはトランザクション内で一時テーブルを使用しない場合、そのテーブルはどのくらいメモリに保持されますか?セッションが終了すると自動的にドロップされますか、または接続が開いている限りメモリに残りますか?DROPMEMORY

** NB明白な答えは、コミットステートメントの前に一時テーブルを削除することかもしれませんが、私はそれを行うことができないとしばらく仮定します。*


編集:もう少し正確にするために、永続的な接続が採用されている場合、テーブルは複数のリクエストを通して持続しますか?これまでのところ、一時テーブルを明示的に削除してそのリソースを解放する必要があると思われます。


更新:コメンターからのアドバイスに基づいて、TEMP MEMORYテーブルを利用できるようにストアドプロシージャを調整する方法を見つけましたがDROP、最後に明示的にそれをすることができます...

ストアドプロシージャを呼び出して残りのTEMPテーブルを使用して実際のクエリの結果を収集するのではCALLなく、3番目の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)

出来上がり!ご意見をお寄せいただきありがとうございます。そして、私がもう少し努力する必要がある理由を教えてくれました。

回答:


17

ストアドプロシージャの一時テーブルについて面白いのは、テーブルの一時的な存在(DB接続の終了時にドロップされる)ではなく、ストアドプロシージャのスコープです。

StackOverflowについて誰かがこの質問をしました:MySQLストアドプロシージャで作成された一時テーブルのスコープ。1年以上経ちましたが、誰も質問に答えませんでしたか?記録をまっすぐにしましょう。実際には、一時テーブルはストアドプロシージャの内外に存在しますが、一時テーブルを使用して実行できるのは、実行中のストアドプロシージャのスコープ内だけです。

よるブック

kdsjx

第5章には、結果セットを別のストアドプロシージャに返す小見出しがあります。

117ページのパラグラフ2に次のように書かれています。

残念ながら、1つのストアドプロシージャから別のストアドプロシージャに結果セットを渡す唯一の方法は、一時テーブルを介して結果を渡すことです。これは厄介な解決策bであり、また、一時テーブルにはセッション全体にわたってスコープがあるため、グローバル変数の使用によって引き起こされる同じ保守性の問題の多くを引き起こします。しかし、ある保存プログラムが別の保存プログラムに結果を提供する必要がある場合、一時テーブルが最善の解決策になる可能性があります。

振り返って StackOverflowの質問、mysqlクライアントからストアドプロシージャと呼ばれる人がいます。mysqlクライアントはストアドプロシージャではないため、結果を確認するためにSELECTを実行する以外、DMLを介してmysqlクライアントレベルで結果を操作することはできません。再帰ストアドプロシージャを呼び出すので、DB接続中は一時テーブルに完全にアクセスできますので安心できます

これがあなたの質問に答えることを願っています。

更新日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テーブルがあるため、これにより他のDB接続が損なわれることはありません。


非常に多くのローランドに感謝します!私は同じ質問をSO(stackoverflow.com/questions/21483448/…)に投稿しました。念のため、より多くの情報を提供しますが、同様の回答を得ました。我々は持続的な接続を採用した場合は、MEMORYテーブルは、複数の要求を通じて持続します、そしてそのパフォーマンスのために、私はこの方法を使用するだろうと仮定していますようだ:私は、フォローアップを提起* REQUIRE明示的に私たちをDROP一時メモリテーブル。私は正しく仮定していますか?
oucil

あなたのUPDATEに関連して、私はそのクエリが再度実行されるまでもはや必要ではない場所にリソースを残すことに関心があると思います、そして私はそうしないかどうかに関係なく明示的にそれを削除する必要があること明らかになっていると思いますする必要があります。
oucil 14年

残念ながら、あるストアドプロシージャから別のストアドプロシージャに結果セットを渡す唯一の方法は、一時テーブルを介して結果を渡すことです。これは、呼び出されたプロシージャで作成された一時テーブルの名前がわかっている場合にのみ、(呼び出し元から)結果セットにアクセスできることを意味しますか?SELECTストアドプロシージャ(DECLARE aCursor CURSOR FOR SELECT ...)でステートメントの結果セットを読み取るために使用できる方法のように、結果セットを読み取る方法ではありませんか?例 DECLARE theCursor CURSOR FOR CALL aProcedure()
ミールイ

2

ほとんどのDBMSでは、特に指定がない限り、または明示的なトランザクションロールバックがない限り、現在の接続が終了するまで一時テーブルが存続します(一部のシステムでは、ロールバックはテーブルのコンテンツにのみ影響し、必要に応じてオブジェクト自体を再配置します) 。テーブルは、それを作成する接続がどれだけ長くても、(デフォルトでは)他の接続からは見えません。

Googleのクイックスキャンは、これがmySQLの動作方法を示しているようです。
http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htmは、「デフォルトでは、データベース接続が終了するとすべての一時テーブルがMySQLによって削除されます。デフォルトでは、すべての一時テーブルはMySQLによって削除されます。データベース接続が終了します」)

ただし、これらの動作を変更する方法はよくあります。たとえば、MS SQL Serverでは、##で始まる名前を付けることにより、現在の接続だけでなく、すべての接続に表示される一時テーブルを作成できます。

混乱を避けるため、一時テーブルが不要になったらすぐに削除します。同じ名前の一時テーブルが作成されたが、現在の接続を使用した以前のアクションで破棄されなかったため、接続プーリングが一時テーブルの作成でエラーを引き起こす前に噛まれました。


テーブルを明示的に削除する方法を見つける必要があることに同意しDROPますが、初期層のIF内で再作成する前にを使用することで、終了した問題を回避します。ご意見ありがとうございます!
oucil 14年

-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 help me..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 ;

CALL usp_GetEngMonthlyChart_Test( '2014-01-01'、 '2015-07-30')


2
コードを投稿するだけでは十分ではありません。これには説明が必要です
ジェームズアンダーソン14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.