Berapa lama tabel MEMORY sementara akan bertahan jika saya tidak menjatuhkannya (MySQL)

13

Saya menggunakan prosedur tersimpan rekursif di MySQL untuk menghasilkan tabel sementara bernama id_list, tapi saya harus menggunakan hasil prosedur itu dalam tindak lanjut pilih kueri, jadi saya tidak bisa DROPtabel sementara dalam prosedur ...

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;

Saat memanggil prosedur, nilai pertama adalah ID teratas dari cabang yang saya inginkan, dan yang kedua adalah tieryang digunakan prosedur selama rekursi. Sebelum loop rekursif ia memeriksa apakah tier = 0dan apakah itu berjalan:

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

Jadi pertanyaan saya adalah: Jika saya tidak tabel DROPsementara MEMORYdi akhir prosedur, atau dalam transaksi saya, berapa lama tabel itu akan bertahan dalam memori? Apakah itu secara otomatis terjatuh setelah sesi berakhir, atau akankah itu tetap ada dalam memori selama koneksi terbuka?

** NB Jawaban yang jelas mungkin untuk menjatuhkan tabel temp sebelum pernyataan komit, tetapi mari kita asumsikan sejenak bahwa saya tidak bisa melakukan itu. *


EDIT : Untuk menjadi sedikit lebih tepat, bagaimana jika koneksi persisten digunakan, akankah tabel bertahan melalui beberapa permintaan? Sejauh ini tampaknya itu akan dan bahwa kita akan perlu secara eksplisit menghapus tabel temp untuk membebaskan sumber daya itu.


PEMBARUAN : Berdasarkan saran dari para komentator, saya telah menemukan cara untuk menyesuaikan prosedur tersimpan saya sehingga saya dapat memanfaatkan tabel TEMP MEMORY, tetapi dapat secara eksplisit DROPdi akhir ...

Daripada hanya memanggil prosedur tersimpan dan menggunakan tabel TEMP yang tersisa untuk mengumpulkan hasil dalam kueri yang sebenarnya, saya telah mengubah CALLformat untuk menggunakan OUTvariabel ketiga seperti:

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

... lalu dalam prosedur tersimpan, saya menambahkan sedetik IF tier = 0di bagian paling akhir dengan yang berikut:

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;

Jadi hasil dari prosedur yang tersimpan sekarang adalah daftar ID yang dipisahkan koma yang kompatibel dengan FIND_IN_SET, dan permintaan akhir telah dimodifikasi sehingga:

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

... sekarang ...

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

Voila! Terima kasih kepada komentator atas masukan Anda, dan untuk memberi saya alasan saya perlu mencoba sedikit lebih keras :)

oucil
sumber

Jawaban:

17

Apa yang lucu tentang tabel sementara dalam prosedur yang disimpan tidak begitu banyak keberadaan sementara tabel (yang akan jatuh setelah penghentian koneksi DB), tetapi ruang lingkup prosedur tersimpan.

Seseorang mengajukan pertanyaan ini pada StackOverflow: Cakupan tabel temp yang dibuat dalam prosedur tersimpan MySQL . Sudah lebih dari setahun dan tidak ada yang menjawab pertanyaan? Biarkan saya meluruskan catatan. Faktanya adalah: Tabel temp ada di dalam dan di luar Prosedur Tersimpan, tetapi Anda bisa melakukan hal-hal dengan tabel sementara hanya di dalam lingkup Prosedur Tersimpan berjalan .

Menurut Kitab

kdsjx

Bab 5 memiliki Subpos Hasil Pengembalian yang diatur ke Prosedur yang Disimpan Lain .

Dikatakan dalam paragraf 2 di halaman 117:

Sayangnya, satu-satunya cara untuk melewatkan set hasil dari satu prosedur tersimpan ke yang lain adalah dengan melewatkan hasil melalui tabel sementara. Ini adalah solusi canggung b, dan - karena tabel sementara memiliki ruang lingkup di seluruh sesi - ini menciptakan banyak masalah rawatan yang sama yang ditimbulkan oleh penggunaan variabel global. tetapi jika satu program tersimpan perlu menyediakan program tersimpan lainnya dengan hasil, maka tabel sementara dapat menjadi solusi terbaik.

Melihat kembali pertanyaan StackOverflow , saya dapat melihat seseorang bernama Stored Procedure dari klien mysql. Karena klien mysql bukan Prosedur Tersimpan, hasilnya tidak dapat memanipulasi tingkat klien mysql melalui DML selain melakukan SELECT untuk melihat hasilnya. Karena Anda memanggil prosedur tersimpan rekursif, Anda dapat yakin bahwa tabel temp sepenuhnya dapat diakses selama durasi Koneksi DB .

Saya harap ini menjawab pertanyaan Anda.

UPDATE 2014-01-31 11:26 EST

Dalam komentar terakhir Anda, Anda berkata

Jika kita menggunakan koneksi terus-menerus, apakah tabel MEMORY akan bertahan melalui beberapa PERMINTAAN, dan tampaknya itu akan, jadi demi kinerja, saya berasumsi bahwa menggunakan metode ini akan * MEMERLUKAN kita untuk secara eksplisit DROP tabel MEMORY sementara. Apakah saya berasumsi dengan benar?

Ya dan Tidak. Saya katakan Ya karena itu adalah salah satu cara untuk melakukannya. Saya mengatakan tidak karena cara lain untuk melakukannya adalah:

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

Apa pun cara yang Anda pilih, operasinya masih sama karena TRUNCATE TABLE menjatuhkan dan membuat ulang tabel. Ini tidak akan membahayakan Koneksi DB lain karena setiap Koneksi memiliki tabel id_list sendiri.

RolandoMySQLDBA
sumber
Rolando SANGAT dihargai! Saya memposting pertanyaan yang sama pada SO ( stackoverflow.com/questions/21483448/... ) kalau-kalau ada lebih banyak perhatian, dan saya mendapat jawaban yang serupa, meskipun kurang informatif. Saya mengajukan tindak lanjut: Jika kita menggunakan koneksi terus-menerus, akankah tabel MEMORY bertahan melalui beberapa PERMINTAAN, dan tampaknya itu akan, jadi demi kinerja, saya berasumsi bahwa menggunakan metode ini akan * MEMERLUKAN kita untuk secara eksplisit DROPMEMORY sementara meja. Apakah saya berasumsi dengan benar?
oucil
Sehubungan dengan UPDATE Anda, saya kira saya lebih peduli dengan meninggalkan sumber daya di tempat yang tidak perlu lagi sampai permintaan itu dijalankan lagi, dan saya pikir itu menjadi lebih jelas bahwa saya harus menghapusnya secara eksplisit terlepas dari apakah saya tidak tidak perlu.
oucil
" Sayangnya, satu-satunya cara untuk melewatkan set hasil dari satu prosedur tersimpan ke yang lain adalah dengan memberikan hasil melalui tabel sementara " . Apakah ini berarti bahwa kita dapat mengakses set hasil (dari pemanggil) hanya ketika kita tahu nama tabel sementara yang dibuat dalam prosedur yang disebut? Bukankah cara membaca set hasil seperti cara yang bisa kita gunakan untuk membaca set hasil dari SELECTpernyataan dalam prosedur tersimpan ( DECLARE aCursor CURSOR FOR SELECT ...)? E. g. DECLARE theCursor CURSOR FOR CALL aProcedure()?
Mir-Ismaili
2

Dalam sebagian besar tabel sementara DBMS bertahan sampai akhir koneksi saat ini kecuali dinyatakan sebaliknya atau kecuali ada rollback transaksi eksplisit (dalam beberapa sistem rollback hanya dapat mempengaruhi konten tabel, meninggalkan objek itu sendiri di sekitar untuk dihuni kembali jika diperlukan) . Tabel tidak akan (secara default) terlihat oleh koneksi lain tidak peduli berapa lama koneksi yang membuatnya berlangsung.

Pemindaian cepat di Google tampaknya mengindikasikan ini adalah cara mySQL beroperasi.
( http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm menyatakan "secara default, semua tabel sementara dihapus oleh MySQL saat koneksi basis data Anda diakhiri. Secara default, semua tabel sementara dihapus oleh MySQL saat koneksi basis data Anda akan dihentikan ")

Seringkali ada cara untuk mengubah perilaku ini. Misalnya di MS SQL Server Anda bisa membuat tabel sementara yang terlihat oleh semua koneksi, bukan hanya yang sekarang dengan memberinya nama yang dimulai ##.

Saya selalu menjatuhkan tabel sementara segera setelah mereka tidak lagi diperlukan untuk menghindari kemungkinan kebingungan. Saya telah digigit sebelumnya di mana penyatuan koneksi mengakibatkan pembuatan tabel sementara menyebabkan kesalahan karena sebuah tabel sementara dengan nama yang sama telah dibuat tetapi tidak dihancurkan dalam tindakan sebelumnya yang menggunakan koneksi saat ini.

David Spillett
sumber
Saya setuju bahwa saya harus menemukan cara untuk menjatuhkan tabel secara eksplisit, tetapi saya menyelesaikan masalah yang Anda selesaikan dengan menggunakan DROPsebelum membuat ulang dalam IF tingkat awal. Terima kasih atas masukan Anda!
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;

/ * kueri yang diberikan berhasil memberikan hasil ... ketika menempatkan kueri ini di USP kemudian menunjukkan kesalahan tolong bantu..proc diberikan di bawah ini * /

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')

Ashutosh
sumber
2
Hanya memposting kode saja tidak cukup baik. Ini perlu penjelasan
James Anderson