Странное поведение Mysql

D
На сайте с 28.06.2008
Offline
1101
882

Есть две таблицы с людьми. Скрипт сравнивает людей из 1 таблицы с людьми из 2-ой таблицы и обновляет несколько полей в таблице №1 согласно логике сравнений.

Всего три запроса, вот их шаблон

   $STH = $db->prepare("SELECT * FROM items WHERE scan IS NULL LIMIT 200");

$UPD = $db->prepare("UPDATE items SET scan = 1, pipl_id = :pipl_id, level = :level WHERE item_id = :item_id LIMIT 1");
$STH2 = $db->prepare("SELECT i.*,c.name as category FROM ddd_pipls_items as i LEFT JOIN ddd_pipls_categories as c ON(i.category_id = c.id) WHERE fullname = :fullname OR shortname = :shortname");

Так как всего записей в таблицах более 300.000 я протестировал из консоли работу скрипта с LIMIT 30.

Проверил в пхп майадмн - 30 записей получили в поле SCAN = 1

Так как крон без геморроя можно самое быстрое поставить на раз в минуту я подобрал лимит чтобы скрипт отрабатывал секунд за 45. Это было лимит =100.

Еще раз проверил - все ок и запустил крон.

Прошло пару часов, я зашел в мунин и смотрю, а нагрузка та стала падать.... (см. скриншоты)

Странно....

Первая мысль мускуль "прогрелся" и скрипт стал отрабатывать быстрее.

Я тормознул крон, и решил протестировать скрипт опять через консоль.

Он отработал за 8 сек!!! Я обрадовался, думаю щас лимит поднимаю и задача закончится за день.

Но решил проверить в пхпмайадмин - еще раз запуская скрипт, отрабатывает за 8 сек, а кол-во записей получивших SCAN = 1 равно 20!!! И это при лимите 100!!!

Короче поигрался с лимитами - скрипт их вообще не придерживается.

Подумал может квери кеш? ДОбавил SQL_NO_CACHE

Скорость скрипта стала по 45 сек с лимитов 100, счетик увеличивался на 5-7 единиц. Просто херня какая то. убрал но кеш, поднял лимит до 200, стало отрабатывать за 55 сек примерно и счетчик увеличивается на 120 примерно. Ну просто НОЛЬ ЛОГИКИ :))) чертовщина

Какие у вас мысли? Почему плавно падает нагрузка и скрипт плавно замедляется, когда ведь ему четко говорят - бери 100 штук записей, анализируй, обновляй!!!

png mysql_innodb_rows-day.png
png cpu-day.png
LEOnidUKG
На сайте с 25.11.2006
Offline
1722
#1

Потому, что LIMIT это не

бери 100 штук записей, анализируй, обновляй!!!

Это сделай всё, что я хочу со всеми записями, а потом отбрось все, кроме 100

Разницу понимаешь? Поэтому LIMIT пишется в конце запроса.

---------- Добавлено 19.01.2019 в 20:55 ----------

отрабатывает за 8 сек, а кол-во записей получивших SCAN = 1 равно 20!!! И это при лимите 100!!!

Может их по факту столько там.

✅ Мой Телеграм канал по SEO, оптимизации сайтов и серверов: https://t.me/leonidukgLIVE ✅ Качественное и рабочее размещение SEO статей СНГ и Бурж: https://getmanylinks.ru/
D
На сайте с 28.06.2008
Offline
1101
#2

Я не привел весь скрипт, может в итоге логики лимит потом и станет в конец. Но работать он должен как я описал. И он работал так в первые запуски. Чего по фатку столько? В таблицу скан записывается 1 когда она обработана, всего записей 350.000.

По идее они должны обрабатываться пачками согласно лимиту. Но если сейчас опять тормознуть крон и запускать срипт вручную через консоль, то кол-во обрабатываемых им записей не поддается логике - 5, 20, 127, но никак не столько сколько задано в лимите

LEOnidUKG
На сайте с 25.11.2006
Offline
1722
#3

выборку запусти без лимита и посмотри сколько там записей вообще.

Также у тебя на полях есть индексы? Случаем не прописано в системе задержка по вставке индексов?

D
На сайте с 28.06.2008
Offline
1101
#4

Я итак знаю сколько записей в 1 и 2 таблице. скрип обновляет поле scan - ставит туда 1, это значит эта запись проанализирована.

В самом конце скрипта есть такое

function lock($name)

{
$lock = sys_get_temp_dir() . "/$name.lock";
$fp = fopen($lock, 'wb');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
return false;
}

register_shutdown_function(function () use ($fp, $lock) {
flock($fp, LOCK_UN);
fclose($fp);
unlink($lock);
});

return true;
}

а в начале такое

if (lock('data_table_level_process')) {

define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_USER', 'test');
define('DB_PASS', 'ПАРОЛЬ');

try {
$db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("SET NAMES utf8");
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}

кодер его написавший тоже без понятия почему скрипт так странно работает.

В таблице №1 есть только первичный ключ на ID и индекс на поле scan

Vin_cent
На сайте с 22.01.2010
Offline
165
#5

Проверь, чтобы были ещё индексы на полях: fullname и shortname.

D
На сайте с 28.06.2008
Offline
1101
#6

Эти поля из таблицы 2, там есть индексы. Вторая таблица вообще не обновляется, только сравнивается. Может этот lock виноват, как корректно убрать его?

D
На сайте с 28.06.2008
Offline
1101
#7

В итоге за ночь скрипт затормозился и делал обновление 2-3 записей при лимите 200.

Как такое возможно?

Простые запросы, четкий лимит. Скрипт начал работать ровно так как от него и ожидали - четко соблюдая лимит и потом затормозился, что может вызвать такое?

vga1
На сайте с 18.02.2007
Offline
251
#8

ВЫ на одновременную работу двух скриптов грешите, что незаконченный первый запуск блокирует второй скрипт? В процессах два скрипта одновременно не видно? Я к тому, что создать lock файл проверки, что пока скрипт не закончил работу, второму не давать запускаться , чтобы одновременно два скрипта не запускались. Или запустить в ручном режиме вообще без лимита в бекграунде командой nohup. Или может в самом скрипте ошибка, выводить на экран больше отладочной информации.

M
На сайте с 17.09.2016
Offline
124
#9

Проверьте логи ядра, не убивается ли Ваш процесс ядром по нехватке памяти ?

---------- Добавлено 20.01.2019 в 11:43 ----------

Ну и в скрипт добавьте "метки" которые будут сбрасываться в лог

Так будет проще понять в чём дело, и на каком этапе ошибка

D
На сайте с 28.06.2008
Offline
1101
#10

В общем поднял я на домашнем опенсервер. Загрузил таблицы, выполняю скрипт с лимитом в 200. Выполнился за 125 сек. Блин долго нет смысла. Проверяю сколько скан = 1. Ровно 200! Вспомниаю что хотел перевести таблицы в мемори. Первожу, выполняю скрипт - 38 сек!!! Смотрю сколько скан = 1, уже 398!!! А не 400 как должно. Еще раз 5 запускаю скрипт - кол-во скан плавно уменьшается от 200 к нулю. Т.е. поведение скрипта полностью такое же как и на сервере. Нужно пересмотреть его логику...

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий