ตาราง 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;

ดังนั้นคำถามของฉันคือ: ถ้าฉันไม่ตารางDROPชั่วคราวMEMORYเมื่อสิ้นสุดขั้นตอนหรือในการทำธุรกรรมของฉันตารางนั้นจะอยู่ในหน่วยความจำนานแค่ไหน มันจะลดลงโดยอัตโนมัติเมื่อเซสชั่นสิ้นสุดหรือจะยังคงอยู่ในหน่วยความจำตราบใดที่การเชื่อมต่อเปิด?

** NB คำตอบที่ชัดเจนอาจวางตาราง temp ก่อนคำสั่ง commit แต่ลองสมมติสักครู่ว่าฉันไม่สามารถทำได้ *


แก้ไข : หากต้องการความแม่นยำมากขึ้นอีกเล็กน้อยจะเกิดอะไรขึ้นหากมีการใช้การเชื่อมต่อแบบถาวรตารางจะคงอยู่ตามคำขอหลายคำขอหรือไม่ จนถึงตอนนี้ดูเหมือนว่ามันจะและเราจะต้องลบตารางชั่วคราวเพื่อเพิ่มทรัพยากรนั้น


อัปเดต : ตามคำแนะนำจากผู้แสดงความคิดเห็นฉันได้พบวิธีการปรับขั้นตอนการจัดเก็บของฉันเพื่อที่ฉันจะสามารถใช้ตารางหน่วยความจำ TEMP ได้ แต่สามารถสรุป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)

Voila! ขอบคุณผู้แสดงความคิดเห็นสำหรับการป้อนข้อมูลของคุณและให้เหตุผลที่ฉันต้องลองให้หนักขึ้นหน่อย :)

คำตอบ:


17

สิ่งที่ตลกเกี่ยวกับตารางชั่วคราวในขั้นตอนการจัดเก็บไม่มากอยู่ชั่วคราวของตาราง (ซึ่งได้รับลดลงเมื่อสิ้นสุดการเชื่อมต่อฐานข้อมูล) แต่ขอบเขตของกระบวนงานที่เก็บไว้

มีคนถามคำถามนี้ใน StackOverflow: ขอบเขตของตารางชั่วคราวที่สร้างขึ้นในขั้นตอนการจัดเก็บไว้ MySQL เป็นเวลากว่าหนึ่งปีแล้วและไม่มีใครตอบคำถาม ขอผมตั้งค่าเร็กคอร์ดให้ตรง ข้อเท็จจริงคือ: ตาราง temp มีอยู่ทั้งภายในและภายนอกกระบวนงานที่เก็บไว้ แต่คุณสามารถทำสิ่งต่าง ๆ ด้วยตารางชั่วคราวภายในขอบเขตของกระบวนงานที่เก็บไว้ที่ทำงานอยู่เท่านั้น

ตามหนังสือ

kdsjx

บทที่ 5 มีชุดผลลัพธ์การส่งคืนหัวข้อย่อยไปยังกระบวนการจัดเก็บอื่น

มันบอกว่าในวรรค 2 ในหน้า 117:

น่าเสียดายที่วิธีเดียวที่จะผ่านชุดผลลัพธ์จากกระบวนงานที่เก็บไว้หนึ่งไปยังอีกกระบวนการหนึ่งคือการส่งผลลัพธ์ผ่านตารางชั่วคราว นี่เป็นวิธีแก้ปัญหาที่น่าอึดอัดใจ b และ - เนื่องจากตารางชั่วคราวมีขอบเขตตลอดทั้งเซสชัน - มันสร้างปัญหาการบำรุงรักษาเดียวกันหลายประการที่เกิดจากการใช้ตัวแปรทั่วโลก แต่ถ้าโปรแกรมที่จัดเก็บไว้หนึ่งโปรแกรมต้องการผลลัพธ์ที่จัดเก็บไว้อีกโปรแกรมหนึ่งตารางชั่วคราวอาจเป็นทางออกที่ดีที่สุด

เมื่อมองย้อนกลับไปที่คำถาม StackOverflowฉันสามารถเห็นคนที่เรียกว่า Stored Procedure จากไคลเอนต์ mysql เนื่องจากไคลเอนต์ mysql ไม่ใช่ Stored Procedure ผลลัพธ์จึงไม่สามารถจัดการกับระดับไคลเอนต์ mysql ผ่าน DML นอกเหนือจากการเลือก SELECT เพื่อดูผลลัพธ์ เนื่องจากคุณเรียกขั้นตอนการเก็บ recursive, คุณสามารถมั่นใจได้ตาราง temp สามารถเข้าถึงได้อย่างเต็มที่สำหรับระยะเวลาของการเชื่อมต่อฐานข้อมูล

ฉันหวังว่านี้ตอบคำถามของคุณ.

อัปเดต 2014-01-31 11:26 EST

ในความคิดเห็นล่าสุดของคุณคุณพูดว่า

หากเราใช้การเชื่อมต่อแบบถาวรตาราง MEMORY จะยังคงอยู่ผ่านการร้องขอหลายรายการและดูเหมือนว่าจะเป็นเช่นนั้นเพื่อประโยชน์ด้านประสิทธิภาพฉันสมมติว่าการใช้วิธีนี้จะ * ขอให้เราลบตาราง MEMORY ชั่วคราวอย่างชัดเจน ฉันถือว่าถูกต้องหรือไม่

ใช่และไม่ฉันพูดว่าใช่เพราะเป็นวิธีหนึ่งที่จะทำ ฉันบอกว่าไม่เพราะมีวิธีอื่นที่จะทำ:

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

ไม่ว่าคุณจะเลือกวิธีใดการดำเนินการจะยังคงเหมือนเดิมตั้งแต่ TRUNCATE TABLE ลดลงและสร้างตารางใหม่ สิ่งนี้จะไม่เป็นอันตรายต่อการเชื่อมต่อฐานข้อมูลอื่น ๆ เนื่องจากแต่ละการเชื่อมต่อมีตาราง id_list ของตัวเอง


ชื่นชมมาก Rolando! ฉันโพสต์คำถามเดียวกันบน SO ( stackoverflow.com/questions/21483448/ … ) ในกรณีที่มันมีตามากกว่านี้และฉันก็คล้ายกันแม้ว่าจะมีคำตอบน้อยลงก็ตาม ฉันโพสต์ติดตามผล: หากเราใช้การเชื่อมต่อแบบถาวรตาราง MEMORY จะยังคงอยู่ผ่านการร้องขอหลายรายการและดูเหมือนว่ามันจะเป็นเช่นนั้นเพื่อประสิทธิภาพการทำงานฉันคิดว่าการใช้วิธีนี้จะ*ขอให้เราDROPทำการลบหน่วยความจำชั่วคราวอย่างชัดเจนโต๊ะ. ฉันถือว่าถูกต้องหรือไม่
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 แล้วแสดงข้อผิดพลาดโปรดช่วยฉันด้วย .. โปรแกรมจะได้รับด้านล่าง * /

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 ;

โทร usp_GetEngMonthlyChart_Test ('2014-01-01', '2015-07-30')


2
การโพสต์โค้ดไม่ดีพอ สิ่งนี้ต้องการคำอธิบาย
James Anderson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.