Geçici bir BELLEK tablosu bırakmazsam ne kadar devam eder (MySQL)


13

Geçici bir tablo adlı oluşturmak için MySQL özyinelemeli bir saklı yordam kullanıyorum id_list, ancak yordam içinde DROPgeçici tablo yapamam bu yüzden bir izleme seçme sorgusu bu yordamın sonuçlarını kullanmanız gerekir ...

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;

Yordamı çağırırken, ilk değer istediğim dalın üst kimliği ve ikincisi tieryordamlar sırasında yordamın kullandığı değerdir . Özyinelemeli döngüden önce çalışıp çalışmadığını kontrol eder tier = 0:

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

: Benim soru yani ben yoksa DROPgeçici MEMORYprosedürün sonunda tablo, ya da benim işlem içinde, ne kadar bu tablo bellekte kalıcı olur? Oturum sona erdiğinde otomatik olarak kesilir mi yoksa bağlantı açık olduğu sürece bellekte kalır mı?

** NB Açık yanıt, taahhüt tablosundan önce geçici tabloyu bırakmak olabilir, ancak bir an için bunu yapamayacağımı varsayalım. *


EDIT : Biraz daha kesin olmak gerekirse, kalıcı bağlantılar kullanılırsa, tablo birden çok istek ile devam edecek mi? Şimdiye kadar öyle olacak ve bu kaynağı boşaltmak için geçici tabloyu açıkça kaldırmamız gerekecek gibi görünüyor.


GÜNCELLEME : Yorumculardan gelen tavsiyelere dayanarak, saklı yordamımı ayarlamanın bir yolunu buldum, böylece TEMP MEMORY tablosunu kullanabiliyorum, ancak DROPsonunda açıkça yapabiliyorum ...

Sadece saklı yordamı çağırmak ve gerçek sorgu sonuçları toplamak için kalan TEMP tablo CALLkullanmak yerine, OUTböyle üçüncü bir değişken kullanmak için biçim değiştirdim :

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

... sonra saklı yordam içinde, IF tier = 0sonuna bir saniye ekledi :

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;

Bu nedenle, saklı yordamın sonucu artık uyumlu bir virgülle ayrılmış kimlik listesi FIND_IN_SETve böylece son sorgu değiştirildi ki:

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

... şimdi ...

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

İşte bu kadar! Yorumcunuz için yorumculara ve bana biraz daha denemem için nedenini verdiğiniz için teşekkürler :)

Yanıtlar:


17

Saklı bir yordamda geçici tablolar hakkında komik olan, tablonun geçici varlığı (DB bağlantısının sonlandırılması üzerine düşer) değil, saklı yordamın kapsamıdır.

Birisi bu soruyu StackOverflow: MySQL saklı yordamında oluşturulan geçici tabloların kapsamı hakkında sordu . Bir yıldan fazla oldu ve kimse soruyu cevaplamadı mı? Rekoru düz ayarlayayım. Gerçek şu ki: Geçici tablo, Saklı Yordamın içinde ve dışında bulunur, ancak geçici tablo ile yalnızca çalışan bir Saklı Yordamın kapsamı içinde bir şeyler yapabilirsiniz .

Göre Kitabı

kdsjx

Bölüm 5, Sonuç Kümelerini Başka Bir Saklı Yordam'a Döndürme alt başlığına sahiptir .

Sayfa 117'deki 2. paragrafta şöyle diyor:

Ne yazık ki, bir sonuç kümesini bir saklı yordamdan diğerine geçirmenin tek yolu, sonuçları geçici bir tablodan geçirmektir. Bu garip bir çözümdür b ve - geçici tablonun tüm oturum boyunca kapsamı olduğundan - global değişkenlerin kullanımıyla ortaya çıkan aynı sürdürülebilirlik sorunlarının çoğunu yaratır. ancak bir depolanmış programın başka bir depolanmış programla sonuç sağlaması gerekiyorsa, geçici bir tablo en iyi çözüm olabilir.

StackOverflow sorusuna baktığımda , mysql istemcisinden Saklı Yordam adı verilen birini görebiliyorum. Mysql istemcisi bir Saklı Yordam olmadığından, sonuçları görmek için bir SELECT yapmak dışında, sonuçlar DML aracılığıyla mysql istemci düzeyini değiştiremez. Özyinelemeli bir saklı yordamı çağırdığından, geçici tabloya DB Bağlantısı süresi boyunca tam olarak erişilebilir olduğundan emin olabilirsiniz .

Umarım bu soruya cevap verir.

GÜNCELLEME 2014-01-31 11:26 EST

Son yorumunda dedin ki

Kalıcı bağlantılar kullanırsak, MEMORY tablosu birden fazla REQUESTS aracılığıyla devam edecek ve öyle görünecek, bu yüzden performans uğruna, bu yöntemi kullanmanın * geçici MEMORY tablosunu açıkça DÜŞÜRMESİ GEREKECEKTİR. Doğru kabul eder miyim?

Evet ve Hayır. Evet diyorum çünkü bunu yapmanın bir yolu var. Hayır diyorum çünkü bunu yapmanın başka bir yolu:

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

Hangisini seçerseniz seçin, TRUNCATE TABLE masayı düşürüp yeniden oluşturduğundan işlem hala aynıdır. Her Bağlantı kendi id_list tablosuna sahip olduğundan bu diğer DB Bağlantılarına zarar vermez.


ÇOK çok takdir Rolando! Aynı soruyu, üzerinde daha fazla göz olması durumunda SO'ya ( stackoverflow.com/questions/21483448/… ) gönderdim ve daha az bilgilendirici de olsa benzer bir cevap aldım. Bir takip ettim: Eğer kalıcı bağlantılar kullanırsak, BELLEK tablosu birden fazla İSTEK yoluyla devam edecek mi ve öyle görünecek, bu yüzden performans uğruna, bu yöntemi kullanmanın * açıkça DROPgeçici BELLEK için bize GEREKLİDİR tablo. Doğru kabul eder miyim?
oucil

UPDATE ile ilgili olarak, sanırım bu sorgu tekrar çalıştırılana kadar artık gerekli olmayan bir kaynağı yerinde bırakmakla daha fazla ilgileniyorum ve sanırım yapmamaya bakılmaksızın açıkça kaldırmam gerektiğini daha açık hale geliyor gerek yok.
oucil

" Ne yazık ki, bir sonuç kümesini bir saklı yordamdan diğerine geçirmenin tek yolu, sonuçları geçici bir tablodan geçirmektir " . Bu, sonuç kümesine (arayandan) yalnızca çağrılan yordamda oluşturulan geçici tablonun adını bildiğimizde erişebileceğimiz anlamına mı geliyor? Sonuç kümesini, SELECTsaklı yordamlarda ( DECLARE aCursor CURSOR FOR SELECT ...) bir ifadenin sonuç kümesini okumak için kullanabileceğimiz gibi okumak için bir yol değil mi? Örneğin. DECLARE theCursor CURSOR FOR CALL aProcedure()?
Mir-Ismaili

2

Çoğu DBMS'de geçici tablolar, aksi belirtilmedikçe veya açık bir işlem geri alımı olmadığı sürece geçerli bağlantının sonuna kadar hayatta kalır (bazı sistemlerde geri alma yalnızca tablonun içeriğini etkileyebilir ve nesnenin kendisini yeniden doldurulması gerekirse bırakabilir) . Tablo, oluşturan bağlantı ne kadar sürerse sürsün (varsayılan olarak) diğer bağlantılara görünmez.

Google'da hızlı bir tarama, mySQL'in nasıl çalıştığını gösteriyor.
( http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm "varsayılan olarak, veritabanı bağlantınız sona erdiğinde tüm geçici tablolar MySQL tarafından silinir" ifadesini kullanır))

Bu davranışları değiştirmenin genellikle yolları vardır. Örneğin, MS SQL Server'da, ## ile başlayan bir ad vererek yalnızca geçerli olanın yerine tüm bağlantılar tarafından görülebilen geçici bir tablo oluşturabilirsiniz.

Olası karışıklığı önlemek için artık gerekli olmadıkları anda geçici tabloları her zaman bırakıyorum. Aynı havuzda geçici bir tablo oluşturulmuş, ancak geçerli bağlantıyı kullanan önceki bir eylemde yok edilmediğinden, bağlantı havuzunun geçici tablo oluşturma hatalarına neden olduğu yerde daha önce ısırıldım.


Masayı açıkça bırakmanın bir yolunu bulmam gerektiğini kabul ediyorum, ancak DROPilk katmanın IF'sinde yeniden oluşturmadan önce kullanarak bitirdiğiniz sorunu çözüyorum. Giriş için teşekkürler!
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;

/ * verilen sorgu başarıyla sonuç verdi ... Bu sorguyu USP'ye koyduktan sonra plz help me hatası gösteriliyorsa ... proc aşağıda verilmiştir * /

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
Sadece kod gönderme yeterli değil. Bunun bir açıklamaya ihtiyacı var
James Anderson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.