삭제하지 않으면 임시 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이고 두 번째 값은 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세 번째 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 항에 나와 있습니다.

불행하게도 하나의 저장 프로 시저에서 다른 저장 프로 시저로 결과 세트를 전달하는 유일한 방법은 임시 테이블을 통해 결과를 전달하는 것입니다. 이 방법은 어색한 해결책입니다. 임시 테이블은 전체 세션에 걸쳐 범위가 있기 때문에 전역 변수를 사용하여 발생하는 동일한 유지 관리 성 문제가 많이 발생합니다. 그러나 하나의 저장된 프로그램이 다른 저장된 프로그램에 결과를 제공해야하는 경우 임시 테이블이 가장 좋은 솔루션이 될 수 있습니다.

StackOverflow 질문을 되돌아 보면 mysql 클라이언트에서 저장 프로 시저라는 사람을 볼 수 있습니다. mysql 클라이언트는 저장 프로 시저가 아니기 때문에 결과를보기 위해 SELECT를 수행하는 것 외에 DML을 통해 결과를 mysql 클라이언트 레벨로 조작 할 수 없습니다. 재귀 저장 프로 시저를 호출하므로 DB 연결 기간 동안 임시 테이블에 완전히 액세스 할 수 있습니다 .

이것이 귀하의 질문에 답변되기를 바랍니다.

업데이트 2014-01-31 11:26 EST

마지막 코멘트에서, 당신은 말했다

영구 연결을 사용하는 경우 MEMORY 테이블은 여러 REQUESTS를 통해 지속되며 성능을 위해이 방법을 사용하면 임시 MEMORY 테이블을 명시 적으로 DROP해야한다고 가정합니다. 내가 올바르게 가정합니까?

예, 아니요. 한 가지 방법이기 때문에 예라고 말합니다. 다른 방법으로 할 수 없기 때문에 아니오라고 말합니다.

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

어떤 방법을 선택하더라도 TRUNCATE TABLE이 테이블을 삭제하고 다시 작성하므로 조작은 여전히 ​​동일합니다. 각 Connection에는 고유 한 id_list 테이블이 있으므로 다른 DB Connection에 영향을 미치지 않습니다.


롤란도에게 대단히 감사합니다! 나는 그것에 대해 더 많은 눈을 얻었을 때를 대비 하여 SO ( stackoverflow.com/questions/21483448/… ) 에 동일한 질문을 게시했으며 정보는 덜 비슷하지만 비슷한 답변을 얻었습니다. 후속 조치를 취했습니다. 영구적 연결을 사용하는 경우 MEMORY 테이블이 여러 요청을 통해 지속되며 성능이 좋을 것이므로이 방법을 사용 DROP하면 임시 MEMORY 를 명시 적으로 지정 해야 한다고 가정합니다 표. 내가 올바르게 가정합니까?
oucil

귀하의 업데이트와 관련하여 쿼리를 다시 실행할 때까지 더 이상 필요없는 리소스를 그대로 두는 것이 더 중요하다고 생각합니다. '아니오 '에 관계없이 명시 적으로 제거 해야한다는 것이 분명해졌습니다. 필요가 없습니다.
oucil

" 불행히도 하나의 저장 프로 시저에서 다른 저장 프로 시저로 결과 세트를 전달하는 유일한 방법은 임시 테이블을 통해 결과를 전달하는 것 입니다. " 이는 호출 된 프로 시저에서 작성된 임시 테이블의 이름을 알고있는 경우에만 호출자로부터 결과 세트에 액세스 할 수 있음을 의미합니까? SELECT스토어드 프로 시저 ( DECLARE aCursor CURSOR FOR SELECT ...) 에서 명령문 의 결과 세트를 읽는 데 사용할 수있는 방법과 같은 결과 세트를 읽는 방법이 아닙니까? 예 : DECLARE theCursor CURSOR FOR CALL aProcedure()?
Mir-Ismaili

2

대부분의 DBMS에서 임시 테이블은 달리 지정하지 않거나 명시적인 트랜잭션 롤백이없는 한 현재 연결이 끝날 때까지 유지됩니다 (일부 시스템에서는 롤백이 테이블의 내용에만 영향을 미쳐 필요한 경우 개체 자체를 다시 채울 수 있음) . 테이블을 작성하는 연결의 지속 시간에 관계없이 테이블은 기본적으로 다른 연결에 표시되지 않습니다.

Google에서 빠른 스캔은 이것이 mySQL의 작동 방식을 나타내는 것으로 보입니다.
( http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm 은 "기본적으로 데이터베이스 연결이 종료되면 모든 임시 테이블이 MySQL에 의해 삭제됩니다"라고 표시합니다)

그래도 이러한 동작을 변경하는 방법이 있습니다. 예를 들어 MS SQL Server에서는 이름이 ##으로 시작하여 현재 연결 대신 모든 연결에 표시되는 임시 테이블을 만들 수 있습니다.

혼란을 피하기 위해 더 이상 필요하지 않은 즉시 임시 테이블을 삭제합니다. 동일한 이름의 임시 테이블이 생성되었지만 현재 연결을 사용하는 이전 작업에서 손상되지 않았기 때문에 연결 풀링으로 인해 임시 테이블이 생성되는 오류가 발생하기 전에 물었습니다.


테이블을 명시 적으로 삭제하는 방법을 찾아야한다는 데 동의하지만 DROP초기 계층의 IF 내에서 다시 작성하기 전에 이전 에 사용한 문제를 해결합니다 . 입력 해 주셔서 감사합니다!
oucil

-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
코드를 게시하는 것만으로는 충분하지 않습니다. 이것은 설명이 필요합니다
James Anderson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.