Một bảng NHỚ tạm thời sẽ tồn tại bao lâu nếu tôi không bỏ nó (MySQL)


13

Tôi đang sử dụng một thủ tục được lưu trữ đệ quy trong MySQL để tạo một bảng tạm thời được gọi id_list, nhưng tôi phải sử dụng các kết quả của thủ tục đó trong một truy vấn chọn tiếp theo, vì vậy tôi không thể DROPlà bảng tạm thời trong quy trình ...

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;

Khi gọi thủ tục, giá trị đầu tiên là ID trên cùng của nhánh tôi muốn và giá trị thứ hai là tierthủ tục sử dụng trong quá trình thu hồi. Trước vòng lặp đệ quy, nó kiểm tra xem tier = 0và nếu nó chạy:

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

Vì vậy, câu hỏi của tôi là: Nếu tôi không DROPđặt MEMORYbảng tạm thời ở cuối quy trình hoặc trong giao dịch của mình, bảng đó sẽ tồn tại trong bộ nhớ bao lâu? Là nó tự động bị hủy khi phiên kết thúc, hoặc nó sẽ vẫn còn trong bộ nhớ miễn là kết nối được mở?

** NB Câu trả lời rõ ràng có thể là bỏ bảng tạm thời trước câu lệnh cam kết, nhưng hãy giả sử trong giây lát rằng tôi không thể làm điều đó. *


EDIT : Nói chính xác hơn một chút, nếu kết nối liên tục được sử dụng, bảng có tồn tại qua nhiều yêu cầu không? Cho đến nay có vẻ như nó sẽ và chúng ta sẽ cần phải loại bỏ rõ ràng bảng tạm thời để giải phóng tài nguyên đó.


CẬP NHẬT : Dựa trên lời khuyên từ những người bình luận, tôi đã tìm ra cách điều chỉnh thủ tục được lưu trữ của mình để tôi có thể sử dụng bảng NHỚ NHỚ, nhưng DROPcuối cùng có thể rõ ràng ...

Thay vì chỉ gọi thủ tục được lưu trữ và sử dụng bảng TEMP còn lại để thu thập kết quả trong truy vấn thực tế, tôi đã thay đổi CALLđịnh dạng để sử dụng OUTbiến thứ ba như sau:

CALL fetch_inheritance_groups('abc123','0',@IDS);

... sau đó trong thủ tục được lưu trữ, tôi đã thêm một giây IF tier = 0ở cuối cùng với phần sau:

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;

Vì vậy, kết quả của thủ tục được lưu trữ bây giờ là danh sách ID được phân tách bằng dấu phẩy tương thích FIND_IN_SETvà do đó, truy vấn cuối cùng đã được sửa đổi để:

WHERE r.Group_ID = 'abc123' OR r.Group_ID IN (SELECT * FROM id_list)

... Hiện tại là ...

WHERE r.Group_ID = 'abc123' OR FIND_IN_SET(r.Group_ID,@IDS)

Voila! Cảm ơn các bình luận viên cho đầu vào của bạn, và đã cho tôi lý do tôi cần phải cố gắng hơn một chút :)

Câu trả lời:


17

Điều buồn cười về các bảng tạm thời trong một thủ tục được lưu trữ không phải là sự tồn tại tạm thời của bảng (được loại bỏ khi chấm dứt kết nối DB), mà là phạm vi của thủ tục được lưu trữ.

Ai đó đã hỏi câu hỏi này trên StackOverflow: Phạm vi của các bảng tạm thời được tạo trong thủ tục lưu trữ MySQL . Đã hơn một năm và không ai trả lời câu hỏi? Để tôi đặt hồ sơ trực tiếp. Thực tế là: Bảng tạm thời tồn tại bên trong và bên ngoài Quy trình được lưu trữ, nhưng bạn chỉ có thể thực hiện mọi việc với bảng tạm thời trong phạm vi của Quy trình được lưu trữ đang chạy .

Theo sách

kdsjx

Chương 5 có một bộ kết quả trả lại phân nhóm cho một thủ tục được lưu trữ khác .

Nó nói trong đoạn 2 trên trang 117:

Thật không may, cách duy nhất để chuyển một tập kết quả từ một thủ tục được lưu trữ sang một thủ tục khác là chuyển các kết quả qua một bảng tạm thời. Đây là một giải pháp khó xử b và - bởi vì bảng tạm thời có phạm vi trong toàn bộ phiên - nó tạo ra nhiều vấn đề bảo trì tương tự được đưa ra bằng cách sử dụng các biến toàn cục. nhưng nếu một chương trình được lưu trữ cần cung cấp kết quả cho một chương trình được lưu trữ khác, thì một bảng tạm thời có thể là giải pháp tốt nhất.

Nhìn lại câu hỏi StackOverflow , tôi có thể thấy ai đó được gọi là Thủ tục lưu trữ từ máy khách mysql. Vì máy khách mysql không phải là Thủ tục được lưu trữ, nên các kết quả không thể được thao tác ở cấp máy khách mysql thông qua DML ngoài việc thực hiện CHỌN để xem kết quả. Vì bạn gọi một thủ tục lưu trữ đệ quy, bạn có thể yên tâm bảng tạm thời có thể truy cập đầy đủ trong suốt thời gian của Kết nối DB .

Tôi mong bạn trả lời câu hỏi này.

CẬP NHẬT 2014-01-31 11:26 EST

Trong bình luận cuối cùng của bạn, bạn đã nói

Nếu chúng tôi sử dụng các kết nối liên tục, bảng MEMOR sẽ tồn tại qua nhiều YÊU CẦU, và có vẻ như vậy, vì lợi ích hiệu suất, tôi cho rằng sử dụng phương pháp này sẽ * YÊU CẦU chúng tôi để DROP rõ ràng bảng MEMOR tạm thời. Tôi có giả định đúng không?

Có và không. Tôi nói Có vì đó là một cách để làm điều đó. Tôi nói không bởi vì một cách khác để làm điều đó là:

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

Dù bạn chọn cách nào, thao tác vẫn giống nhau vì TRUNCATE TABLE giảm xuống và tạo lại bảng. Điều này sẽ không gây hại cho các Kết nối DB khác vì mỗi Kết nối có bảng id_list riêng.


RẤT nhiều đánh giá cao Rolando! Tôi đã đăng câu hỏi tương tự trên SO ( stackoverflow.com/questions/21483448/ cấp ) chỉ trong trường hợp nó nhận được nhiều ánh mắt hơn và tôi nhận được câu trả lời tương tự, mặc dù ít thông tin hơn. Tôi đã đưa ra một theo dõi: Nếu chúng tôi sử dụng các kết nối liên tục, bảng MEMOR sẽ tồn tại qua nhiều YÊU CẦU, và có vẻ như vậy, vì lợi ích hiệu suất, tôi cho rằng sử dụng phương pháp này sẽ * YÊU CẦU chúng tôi để rõ ràng DROPNHỚ bàn. Tôi có giả định đúng không?
cilil

Liên quan đến CẬP NHẬT của bạn, tôi đoán tôi quan tâm hơn đến việc để lại một tài nguyên không còn cần thiết cho đến khi truy vấn đó được chạy lại và tôi nghĩ rằng rõ ràng hơn là tôi nên xóa nó bất kể tôi có không ' t cần
cilil

" Thật không may, cách duy nhất để chuyển một tập kết quả từ một thủ tục được lưu trữ sang một thủ tục khác là chuyển các kết quả qua một bảng tạm thời " . Điều này có nghĩa là chúng ta chỉ có thể truy cập tập kết quả (từ người gọi) khi chúng ta biết tên của bảng tạm thời được tạo trong thủ tục được gọi? Không phải là cách đọc tập kết quả giống như cách chúng ta có thể sử dụng để đọc tập kết quả của SELECTcâu lệnh trong các thủ tục được lưu trữ ( DECLARE aCursor CURSOR FOR SELECT ...) sao? Ví dụ. DECLARE theCursor CURSOR FOR CALL aProcedure()?
Mir-Ismaili

2

Trong hầu hết các bảng DBMS tạm thời tồn tại cho đến khi kết thúc kết nối hiện tại trừ khi có quy định khác hoặc trừ khi có một giao dịch rõ ràng (trong một số hệ thống, việc khôi phục chỉ có thể ảnh hưởng đến nội dung của bảng, khiến cho đối tượng xung quanh bị lặp lại nếu cần) . Bảng sẽ không (theo mặc định) hiển thị cho các kết nối khác cho dù kết nối tạo ra nó kéo dài bao lâu.

Quét nhanh trên Google dường như cho thấy đây là cách myQuery hoạt động.
( http://www.tutorialspoint.com/mysql/mysql-t tạm- tables.htm trạng thái "theo mặc định, tất cả các bảng tạm thời bị xóa bởi MySQL khi kết nối cơ sở dữ liệu của bạn bị chấm dứt. Mặc định, tất cả các bảng tạm thời bị xóa bởi MySQL khi kết nối cơ sở dữ liệu của bạn bị chấm dứt ")

Thường có nhiều cách để thay đổi những hành vi này. Chẳng hạn, trong MS SQL Server, bạn có thể tạo một bảng tạm thời hiển thị cho tất cả các kết nối thay vì chỉ bảng hiện tại bằng cách đặt tên bắt đầu là ##.

Tôi luôn bỏ các bảng tạm thời ngay khi chúng không còn cần thiết để tránh nhầm lẫn có thể. Tôi đã bị cắn trước khi kết nối nhóm kết quả dẫn đến việc tạo bảng tạm thời gây ra lỗi vì một bảng tạm thời cùng tên đã được tạo nhưng không bị hủy trong một hành động trước đó sử dụng kết nối hiện tại.


Tôi đồng ý rằng tôi nên tìm cách bỏ bảng một cách rõ ràng, nhưng tôi khắc phục được vấn đề bạn đã giải quyết bằng cách sử dụng DROPtrước khi tạo lại trong IF ban đầu của lớp. Cảm ơn vì đầu vào của bạn!
cilil

-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;

/ * truy vấn đã cho kết quả thành công ... khi đặt truy vấn này vào USP rồi hiển thị lỗi, xin hãy giúp tôi..proc được đưa ra dưới đây * /

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 ;

GỌI usp_GetEngMonthlyChart_Test ('2014-01-01', '2015-07-30')


2
Chỉ đăng mã là không đủ tốt. Điều này cần một lời giải thích
James Anderson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.