Задача, в общем-то, не новая, но проблема возникла в том, что таблицы достаточно массивные для нужной операции (~80к). А суть состоит в том, что в таблице "A" нужно установить определенному полю значение "0", если в таблице "B" нет записи с таким же ID и штрих-кодом. Пробовал запросы и с помощью LEFT OUTER JOIN, и NOT EXISTS, но результат один - через пять минут финал по таймауту. Увеличивать max_execution_time не выход, т.к. и пять минут как-то многовато, тем более, что операция будет проводится ежедневно. Вот хочу посоветоваться, какие могут быть альтернативные варианты. На всякий случай, покажу запрос, который нормально работал, по в таблицах было масло записей (до 1к): PHP: <?php $query = "UPDATE `A` LEFT OUTER JOIN `B` ON `A`.`barcode` = `B`.`barcode` AND `A`.`id` = `B`.`id` SET `A`.`field` = 0 WHERE `B`.`barcode` IS NULL";
Выборка из источника по условию быстро проходит? Отключение индексов на время обновления целевой таблицы допустимо?
@Ganzal я бы не сказал, что очень быстро. К примеру, поиск по тому же штрих-коду и id, занимает около 0.0490 сек. Отключить индексы - допустимо. P.S. Наверно нужно добавить, что вторая таблица существует только для импорта данных. В неё заливаются данные из XML-файла, а потом проводится ряд обновлений в рабочих таблицах. Все эти операции (их всего 7), выполняются за секунд 20, а вот эта последняя всю картину портит.
Да, на PHP. Пакетами - это в каком смысле? Разбить XML-файл на несколько небольших и пройтись по ним поочерёдно или частями обновлять в мускуле?
Ну что-то типа. Ну или выбрать все пары баркод+первичный ключ из главной таблицы, разместить их в массиве, выбрать баркоды из второй таблицы, поудалять ключи с этими баркодами из массива, и потом сделать один или несколько запросов вида "update A set field = 0 where id in (.....)". По идее для первичного ключа индекс будет быстро работать. А ты explain-ить запрос не пробовал? Мускул не находит в нем проблем? Может там где индекс какой пропадает. Или даже не создан.
В общем, способом научного тыка, определил достаточно оптимальный способ, на который так же натолкнул @Ganzal. Выбрал из временной таблицы баркод и id, сконкатенировав их в самом запросе через дефис, полученный массив флипнул (isset работает быстрее, чем in_array) и выбрал баркод и id по отдельности из основной таблицы: PHP: <?php // массив для отсутвующих ID-шников $missing_id = []; // Полученный в итоге массив из временной таблицы, типа такого $tmp_keys = [ '123456789-555' => 1, '987654321-123' => 2, /* ... */ ]; // Выбрали баркод и ID из целевой таблицы, проверяем в цикле while ($line = $sth->fetch(\PDO::FETCH_ASSOC)) { if ( !isset($tmp_keys[$line['barcode'] . '-' . $line['id']]) ) { $missing_id[] = $line['id']; } } // Дальше можно проверить размер $missing_id, // если большой, то разбить на части array_chunk и обновляем записи в БД Результат более чем приемлемый. Именно эта операция, которая ранее занимала 5+ минут, сейчас в среднем выполняется за 0.305 сек! Не буду грешить на MySQL, т.к. тормоза с предыдущим вариантом пока для меня остались загадкой, но пхп справился отлично.