Table 'table_name' doesn't exist.

Тема в разделе "Базы данных", создана пользователем Jarhead, 13 ноя 2018.

Модераторы: latteo
  1. Jarhead

    Jarhead

    Регистр.:
    17 июн 2011
    Сообщения:
    396
    Симпатии:
    141
    При обновлении интернет магазина, создается временная таблица, после занесения данных в которую, выполняется хранимая процедура:

    Код:
    DELIMITER $$
    CREATE DEFINER=`root`@`%` PROCEDURE `sync_fl`()
    BEGIN
      # READ ROWS COUNT IN ALL NEW TABLES AND SHOW ERROR IF ONE IS EMPTY
      DROP TABLE IF EXISTS `sh_prod_im__`;
      ALTER TABLE `sh_prod_im` RENAME TO `sh_prod_im__`;
      ALTER TABLE `sh_prod_im_` RENAME TO `sh_prod_im`;
    END$$
    DELIMITER ;
    Интернет-магазин имеет много посещений в день и видать кто то ловит момент переименования таблицы и возникает ошибка, как можно оптимизировать данный процесс чтобы подобных проблем не возникало? Читал что процесс изменения названия таблицы занимает 0.10 sec и это не подходит.
     
  2. latteo

    latteo Эффективное использование PHP, MySQL

    Moderator
    Регистр.:
    28 фев 2008
    Сообщения:
    1.596
    Симпатии:
    1.508
    Оберни в транзакцию.
    Попробуй избавится от хранимки.
    Возможно результат есть смысл кешировать и шарить для разных пользователей.
     
    ponoroshca нравится это.
  3. ElenaBeck123!

    ElenaBeck123! Создатель

    Регистр.:
    24 май 2017
    Сообщения:
    18
    Симпатии:
    3
    а зачем писать в темп-таблицу а потом переименовывать ? что за данные в таблице, обновлять не получиться сразу в ней ?
     
  4. Jarhead

    Jarhead

    Регистр.:
    17 июн 2011
    Сообщения:
    396
    Симпатии:
    141
    Есть таблица, с информацией о фотографиях товаров, фотографии товаров переодически/часто могут меняться, кол-во фотографий в большую или меньшую сторону, их очередность или ID фотографий. Обновление происходит по требованию или раз в час. Данные приходят о всех товарах целиком, нужно обновлять данные эти так, чтобы клиенты интернет-магазина не испытывали неудобств, не попадали на блокировку записей/смену записей, вообщем для клиентов обновление должно быть полностью незаметным, т.е. моментальным. Insert в рабочую таблицу без транзакции, откуда происходит селект, категорически не возможен. Данные все должны обновится одновременно и моментально. Вопрос как это сделать?

    Пока в черновике записан вот такой вариант, но я не до конца думаю что он удачный:

    У меня уже есть таблица с данными о товарах, откуда берется инфа на сайт:

    Код:
    CREATE TABLE `test` (
      `prod` int(10) unsigned NOT NULL,
      `type` int(10) unsigned NOT NULL,
      `pict` int(10) unsigned NOT NULL,
      `updated` int(1) unsigned DEFAULT '1',
      PRIMARY KEY (`prod`,`type`,`pict`)
    ) ENGINE=InnoDB;
    Далее я обновляю эту таблицу со склада:

    Код:
    DROP TEMPORARY TABLE IF EXISTS `test123`;
    
    CREATE TEMPORARY TABLE `test123` (
        `prod` int(10) unsigned NOT NULL,
            `type` int(10) unsigned NOT NULL,
            `pict` int(10) unsigned NOT NULL,
            PRIMARY KEY (`prod`,`type`,`pict`)
            ) ENGINE = MEMORY;
    
    insert into `test123` values (1,1,1),(2,2,2);
    Далее я запускаю хранимую процедуру с транзакцией:

    Код:
    DELIMITER $$
    CREATE DEFINER=`root`@`%` PROCEDURE `sync_fl2`()
    BEGIN
    
    DECLARE exit handler for sqlexception
      BEGIN
        -- ERROR
      ROLLBACK;
    END;
    
    DECLARE exit handler for sqlwarning
    BEGIN
        -- WARNING
    ROLLBACK;
    END;
    
    START TRANSACTION;
    
      UPDATE `test` SET `updated` = 0;
    
      INSERT INTO `test` (`prod`,`type`,`pict`)
        SELECT `prod`,`type`,`pict`
        FROM `test123`
        ON DUPLICATE KEY UPDATE `updated` = 1;
    
      DELETE FROM `test` WHERE `updated` = 0;
    
    COMMIT;
    END$$
    DELIMITER ;
    Код:
    DROP TEMPORARY TABLE IF EXISTS `test123`;
    Смущает что чисто теоритически если во время обновления из памяти произойдет сбой то данные обновятся частично и это можно будет отловить только визуально и нужно будет работать с фиксом максимального размера таблицы в памяти.
     
    Последнее редактирование: 14 ноя 2018
  5. ElenaBeck123!

    ElenaBeck123! Создатель

    Регистр.:
    24 май 2017
    Сообщения:
    18
    Симпатии:
    3
    ой и на городили! какой еще сбой в памяти :) работая с транзакций, при правильном построение процедуры вам гарантирован откат до начального состояния (до момента измения) таблицы. Это раз. Когда обновляете данные в таблице с транзакцией, пока транзакция не завершена, пользователю отдаются данные на момент до начала изменения. Тоесть он и не видет что идет обновление, я потом бац, обновляет страницу, а данные уже другие > транзакция закоммителась. То, что Вы делаете в временной таблицей / insert, переимменовыванием, все муторно и до боли не правильно. Мое профессиональное мнение.
     
    latteo нравится это.
  6. Jarhead

    Jarhead

    Регистр.:
    17 июн 2011
    Сообщения:
    396
    Симпатии:
    141
    Это черновик, пока создается просто таблица обычная, заполняется, а потом из нее уже транзакцией заполняется другая, а как бы Вы сделали если приходили бы данные в массиве и нужно было бы удалять и после заполнять существующую таблицу из которой делается селект на сайт?
     
  7. ElenaBeck123!

    ElenaBeck123! Создатель

    Регистр.:
    24 май 2017
    Сообщения:
    18
    Симпатии:
    3
    Есть таблица, это ваша основа. Делайте в нее вставку, обновление, удаление.

    Начну с конца, самое противное это удаление сотни, тысячи на наконец миллионов записей (которые больше не нужны) не блокируя таблицу, делается это частями, причем логика вывода данных из таблиц во фронтенд должна основываться на каком нибудь флаге. Тоесть SELECT * FROM xxx WHERE Deleted = 0. Тоесть все что Deleted = 1 пользоваться так и так не увидет, а вы сможете частями, когда захотите, например ночью, когда активность под 0% подчищать таблицу: DELETE xxx WHERE Deleted = 1 LIMIT x, делается в цикле пока есть что удалять. Кроме того, в любой таблице всегда (просто примите это за правило) должно быть поле даты вставки/обновления записи), можно разделить на два поля, можно оставить в одном: TIMESTAMP, его писать во время Insert или Update: NOW()

    Остаеться добавить (INSERT) и обновить(UPDATE), при чем не только записи но и сам Флаг Deleted = 1 у тех записей, которые больше не нужны.
    Есть несколько способов, нужно выбрать из условий, количество записей, частоты обновления, в конце концов версии SQL (MySQL),
    но то что я от вас уловила, сделала бы так:

    1. Найти максимальную дату обновление: SELECT MAX(Timestamp) FROM xxx, сохранить значение это в переменную
    2. При помощи INSERT INTO + ON DUPLICATE KEY UPDATE вставить новые записи и обновить существующие (на основе Primary Keys).
    3. Обновить флаг Deleted у всех записей у которых TIMESTAMP оказался старее вашей переменной из пункта 1: DELETE FROM xxx WHERE Timestamp < @Timestamp.
    Посколько значение не обновилось, значит и обновления больше не пришло, тоесть можно удалить. Все зависит конечто от Бизнес-Логики.
    4. Ночью подчистить таблицу, как указано выше.

    Все пункты (первый можно вынести) выполняются конечно в транзакции.
    Все, вроде ничего сложного ...
     
    latteo нравится это.