November 2019

S M T W T F S
      12
34 5 678 9
10111213141516
17181920212223
24252627282930

Style Credit

Expand Cut Tags

No cut tags

December 5th, 2012

dil: (Default)
Wednesday, December 5th, 2012 09:35 pm

Имеется скрипт. Выполняет довольно простую работу:
соединяется с базой данных (Informix, как водится), создаёт временную таблицу, заполняет её данными из других таблиц.
Потом запускает на эту таблицу SELECT COUNT(*), ну так, чисто для отчётности, и выводит это количество в лог.
Потом создаёт в таблице индекс для ускорения последующих операций и запускает UPDATE STATISTICS, чтоб индекс заработал.
Затем удаляет из таблицы некоторые ненужные данные посредством DELETE, опять запускает SELECT COUNT(*) и… внезапно случается облом:

execute failed: SQL: -710: Table has been dropped, altered or renamed.

Сначала подумали, что в скрипте что-то не то. Но его не меняли уже больше года, а ошибка появилась лишь несколько месяцев назад, до этого всё нормально работало.

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

Потом подумали, что может это на сервере регулярно проводятся какие-то работы как раз когда скрипт по крону запускается. Но нифига, он падает в одном и том же месте в любое время дня и ночи. Вот пока идёт первоначальный INSERT, таблица есть, первый SELECT — есть, DELETE — всё ещё есть, а на следующем SELECT‘е через пару секунд — уже нет. Мистика какая-то..

Чудес не бывает. Через пару недель исследований грабли были найдены. Они оказались очень красивыми. Естественно, я не смог мимо них пройти, не наступив. Попробуйте угадать, что это было.

Подсказка: скрипт использует перловый DBI. То есть, запросы сначала подготавливаются посредством prepare(), а потом уже выполняются вызовом execute(). Запрос про SELECT COUNT(*) запускается несколько раз, после каждого изменения в таблице, но он всегда одинаковый, поэтому для него применяется prepare_cached(), это немножко ускоряет работу.

Оригинал этой записи в личном блоге.
Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме.