Як довго буде зберігатися тимчасова таблиця ПАМ'ЯТЬ, якщо я її не скидаю (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;

При виклику процедури перше значення - це верхній ідентифікатор потрібної мені гілки, а друге - це те, 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таблиці в кінці процедури або в рамках моєї транзакції, як довго ця таблиця збережеться в пам'яті? Чи автоматично відміняється після закінчення сеансу, чи залишиться в пам'яті, поки з'єднання відкрите?

** Примітка. Очевидною відповіддю може бути відкинути таблицю тимчасових тем перед початком заяви, але давайте на мить припустити, що я не можу цього зробити. *


EDIT : Якщо бути більш точним, що, якщо застосовуються стійкі з'єднання, таблиця зберігатиметься через кілька запитів? Поки здається, що це буде і що нам потрібно буде явно видалити темп-таблицю, щоб звільнити цей ресурс.


ОНОВЛЕННЯ : Спираючись на поради коментаторів, я знайшов спосіб коригувати свою збережену процедуру, щоб я міг використовувати таблицю ПАМ’ЯТЬ ТЕМП, але зможу явно 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;

Таким чином, результат збереженої процедури тепер є розділеним комою списком ідентифікаторів, сумісних з 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

Що смішно щодо тимчасових таблиць у збереженій процедурі - це не стільки перехідне існування таблиці (яка потрапляє після припинення з'єднання БД), скільки обсяг збереженої процедури.

Хтось задав це питання в StackOverflow: Обсяг темп-таблиць, створених у збереженій процедурі MySQL . Минуло більше року, і ніхто не відповів на запитання? Дозвольте мені встановити рекорд. Справа в тому, що: таблиця temp існує всередині та зовні Зберігається процедури, але ви можете робити речі з тимчасовою таблицею лише в межах запущеної процедури зберігання .

Згідно з Книгою

kdsjx

У главі 5 є підзаголовка Повернення наборів результатів до іншої збереженої процедури .

У пункті 2 на сторінці 117 написано:

На жаль, єдиний спосіб передати набір результатів із однієї збереженої процедури в іншу - це передача результатів через тимчасову таблицю. Це незручне рішення b, і - оскільки тимчасова таблиця має обсяг упродовж усього сеансу - вона створює багато однакових проблем з ремонтом, які виникають у результаті використання глобальних змінних. але якщо одна збережена програма потребує надання іншої збереженої програми з результатами, тимчасова таблиця може бути найкращим рішенням.

Озираючись назад на питання StackOverflow , я бачу кого - то під назвою збереженої процедури від клієнта MySQL. Оскільки клієнт mysql не є збереженою процедурою, результати не можуть бути маніпульовані рівнем клієнта mysql через DML, крім того, щоб зробити SELECT, щоб побачити результати. Оскільки ви викликаєте рекурсивно збережену процедуру, ви можете бути впевнені, що таблиця тимчасово доступна повністю протягом тривалості з'єднання з БД .

Я сподіваюся, що це відповість на ваше запитання.

ОНОВЛЕННЯ 2014-01-31 11:26 EST

У своєму останньому коментарі ви сказали

Якщо ми будемо використовувати стійкі з'єднання, чи збережеться таблиця ПАМ’ЯТОКУ через декілька ЗАПИТІВ, і, здається, це буде, тому задля продуктивності, я припускаю, що, використовуючи цей метод, * ПОТРЕБИТИсь ми явно ЗРОБИТИ тимчасову таблицю ПАМ’ЯТЬ. Чи правильно я припускаю?

Так і ні. Я кажу так, тому що це один із способів зробити це. Я кажу "ні", тому що інший спосіб зробити це:

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

Який би спосіб ви не вибрали, операція залишається тією ж, оскільки TRUNCATE TABLE опускає та відтворює таблицю. Це не зашкодить іншим з'єднанням БД, оскільки для кожного з’єднання є своя таблиця ідентифікаторів id_list.


ДУЖЕ високо оцінив Роландо! Я написав те саме запитання на SO ( stackoverflow.com/questions/21483448/… ) на всякий випадок, якщо на нього з’явилося більше очей, і я отримав подібні, хоча і менш інформативні, відповіді. Я створив подальше спостереження: якщо ми будемо використовувати стійкі з'єднання, чи буде таблиця ПАМ’ЯТЬ зберігатися через декілька ЗАПИТІВ, і, здається, це буде, тому для ефективності, я припускаю, що використання цього методу * ПОТРЕБИТЬ нас явно DROPтимчасової ПАМ'ЯТІ стіл. Чи правильно я припускаю?
унциль

Що стосується вашої ОНОВЛЕННЯ, я думаю, що я більше переймаюся тим, щоб залишити ресурс на місці, який більше не потрібен, поки цей запит не буде запущений знову, і я вважаю, що стає очевиднішим, що я повинен видалити його явно незалежно від того, чи не роблю я ' не потрібно.
oucil

" На жаль, єдиний спосіб передати набір результатів із однієї збереженої процедури в іншу - це передача результатів через тимчасову таблицю " . Чи означає це, що ми можемо отримати доступ до набору результатів (від абонента) лише тоді, коли дізнаємося ім’я тимчасової таблиці, що створюється в називається процедурі? Чи не спосіб прочитати набір результатів, як спосіб, який ми можемо використовувати для читання набору результатів SELECTоператора у збережених процедурах ( DECLARE aCursor CURSOR FOR SELECT ...)? E. g. DECLARE theCursor CURSOR FOR CALL aProcedure()?
Мір-Ісмаїлі

2

У більшості СУБД тимчасові таблиці зберігаються до кінця поточного з'єднання, якщо не вказано інше або якщо не існує явного відкату транзакцій (у деяких системах відкат може впливати лише на вміст таблиці, залишаючи сам об'єкт навколо репопуляції за потреби) . Таблиця не буде видимою для інших з'єднань незалежно від того, як довго триватиме з'єднання, яке її створює.

Швидке сканування в Google, схоже, свідчить про те, як працює mySQL.
( http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm зазначається, що "за замовчуванням всі MySQL видаляються тимчасовими таблицями після припинення з'єднання з базою даних")

Хоча часто є способи змінити цю поведінку. Наприклад, у MS SQL Server ви можете створити тимчасову таблицю, яку можна побачити всім з'єднанням, а не лише поточній, давши їй ім'я, починаючи з ##.

Я завжди відкидаю тимчасові таблиці, як тільки вони більше не потрібні, щоб уникнути можливої ​​плутанини. Я був укушений раніше, коли об'єднання з'єднань призводило до створення тимчасової таблиці, що спричиняло помилки, оскільки тимчасова таблиця з таким самим іменем була створена, але не знищена в попередній дії, яка використовувала поточне з'єднання.


Я погоджуюсь, що я повинен знайти спосіб явно скинути таблицю, але я вирішу проблему, яку ви закінчили, використовуючи DROPпопереднє відтворення в рамках ІФ початкового рівня. Дякуємо за ваш внесок!
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, допоможіть мені. Програма наведена нижче * /

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
Просто розміщення коду недостатньо добре. Це потребує пояснення
Джеймс Андерсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.