Довелось мне работать в местном интернет-провайдере. Помимо предоставления телекоммуникационных услуг, фирма зарабатывала на создании различных тематических сайтов. Одним из них был сервис по отсылке SMS-сообщений, которые клиенты нашей сети могли отправлять бесплатно.
Я имел отношение к разработке этого сервиса и обслуживал всех клиентов в случае возникновения проблем. Все правки производились непосредственно в консоли базы данных, потому как админку было писать недосуг.
В один прекрасный день клиент пришёл прямо к нам в офис и попросил поменять пароль на его логин в SMS-системе. Быстро найдя в базе номер его записи, я слепым десятипальцевым методом быстро ввожу типичный запрос:
update users set password='newpass' where id - 1234;
...и жму Enter. Вместо знака равенства нажалась клавиша «минус». В результате база данных, вычислив разность между номерами клиентов и заданным числом, поменяла пароли всем, кроме этого клиента.
Следующие два часа ушли на восстановление паролей недельной данности, а ещё где-то месяц мы отвечали на гневные звонки тех, кто за эту неделю менял свой пароль.
Один из серверов был сильно перегружен клиентскими сайтами и в конце концов перестал отдавать контент: пошел в своп, а load average зашкаливал за полсотни. Начинаем вместе с клиентом выяснять, чем же его так. В выводе top налицо активно лопающий память MySQL-сервер, каковым фактом мы радуем клиента и рекомендуем оптимизировать запросы. Клиент отвечает: «Сайт не использует базу данных этого сервера, а работает с удалённой базой».
Сообщаем клиенту, что его сайт на его же сервере не один, и остальные всё-таки потребляют ресурсы и «укладывают» машину. Ответ клиента ошеломил:
— Ммм, а сколько сайтов находится на нашем сервере, и каких именно?
Несколько лет назад наша контора внедряла большую ERP-систему в большой конторе. Всё было настроено, отлажено, проверено, данные загружены. Наступило замечательное время, которое у консультантов называется UAT. Восхищённые/раздражённые юзеры полезли грязными руками тыкать в кнопочки. Одним из юзеров был важный дядя (не Сам, но почти).
Итак, модуль по работе с кадрами. Дядя, не мудрствуя лукаво, запрашивает свои собственные данные и выпадает в осадок. Мало того, что он отображается в системе как женщина, так он (она?) ещё и беременный! Так как кодят систему в основном индусы, огрехи всплывают часто. Как оказалось, забеременеть можно не только по естественным причинам, но и в результате неправильного использования nvl и decode.
Ведь обещали миллион условных енотов первому мужчине, который родит. Можно сказать, дядя шел к успеху, но не подфартило. Исправленный код выпустили через неделю. А какая была мечта!
Много лет в крупном операторе фиксированной связи российского масштаба не было постоянного и квалифицированного системного администратора. Люди приходили и уходили, а знания, пароли и учётные записи уходили вместе с ними. Сервера безвозвратно падали, с ними падал софт, включая базы данных, хитрый, созданный ещё в советское время биллинг, подсистемы программирования кристаллов таксофонных карт и прочее.
Вот уже не осталось носителей знаний, и даже некому было поставить клиент Navision Axapta. Каково же было моё изумление, когда хрупкая девушка попросила меня подойти к ней! На экране — удалённая оснастка, вход в локальную базу и какой-то мелкий вопрос, как правильно делать бэкап. Оказалось, что многие годы эта героическая девушка из бухгалтерии по инструкции еженедельно делала бэкап самой важной базы, как ей и заповедовал один из основоположников всей этой системы.
Был я айтишником в одном турагентстве. Как-то, шерстя базу данных, я нашёл информацию о ценах в отелях на ближайшие три года. Спрашиваю у генерального директора, как это так: то ли у нас ясновидец в штате появился, то ли отели по три года не меняют цены в условиях инфляции? Босс ответил, что данные туда попали по ошибке, и их надо удалить.
Всего один короткий запрос. Всего две забытые кавычки:
delete from prices where price_date>unix_timestamp(2009-12-31)
Сервер радостно подсчитал: 2009 – 12 – 31 = 1968. Как и было заказано, база данных грохнула цены на все даты позже 1968 секунд от начала юникс-эпохи (то есть после 0 часов 32 минут 42 секунд 1 января 1970 года). На тот момент не существовало не только самой фирмы, но даже и самого гендиректора.
В итоге все отели лишились всех цен. Вытаскивать в авральном режиме из бэкапов несколько сотен тысяч строк вручную было ой как весело...
Говорят, что если усадить миллион обезьян за печатные машинки, то с ненулевой вероятностью одна из них наберет «Войну и мир». У одной обезьяны, похоже, получился CMS.
Отдел поддержки клиентских серверов датацентра. Приходит клиентское письмо с жалобой: «После обновлений базы товаров нашего интернет-магазина сайт перестаёт работать и вообще». Сайт вольготно размещён в одиночку на сервере с двухъядерным процессором и 2 ГБ памяти — проблем с производительностью быть не должно. Прошу пнуть нас именно в момент обновлений.
Дожидаюсь ответа «вот сейчас не работает!» Смотрю — на машине оба ядра под завязку нагрузил MySQL. Логинюсь в «мускуль», даю запрос show full processlist. Изумляюсь — терминал виснет наглухо. Передёрнув терминал и залогинившись обратно на машину, запускаю тот же запрос с выводом в файл. Смотрю в результаты: сервер отрабатывает два запроса общей длиной в 1,2 с копейками мегабайта.
Как выяснилось, чудо-фронтэнд магазина выгребал какие-то данные запросом вида «Select * from Таблица where productID='такой-то' and enabled=1 or productID='еще_какойто' and enabled=1 or...», и так до упора. Несчастный MySQL вдумчиво проверял каждую строку немаленькой таблицы на соответствие десяткам тысяч логических условий.
Клиенту отписал, приложив результаты show full processlist. Молчит уже сутки. Видимо, проникается идеей...
Сижу себе вечером дома, пересобираю компьютер, плавненько добираюсь до распределения информации на винчестеры, раздаю задания несчастному Акронису, запускаю его работать и иду на кухню пить чаёк.
Душевное равновесие начал нарушать мобильник. Заговорив голосом сменщика, он слёзно закричал о том, что всё пропало. После оказания скорой антисуицидальной помощи оказалось, что это криворукое тело по ошибке снесло всю базу данных фирмы. Хватаюсь за голову, но тут же успокаиваюсь: предвидя такой исход, я время от времени бэкаплю базу.
Наливаю чаёк, возвращаюсь в комнату к компьютеру, пытаюсь вернуть себе душевный покой. Акронис покорно копирует раздел, на котором находится тот самый бэкап. Лампочка над головой начинает неслабо моргать. «Напруга!» — проносится в голове. Перед глазами всплывают картины бурной молодости: сожженные сетевухи во время грозы в общаге, несколько блоков питания, отказавшихся питаться тем, что было в розетке... От сердца снова отлегает — компьютер-то воткнут через фильтр! За пять секунд до достижения мной стабильного уровня душевного равновесия лампочка тухнет.
Первые полсекунды я в священном ужасе смотрю на монитор, на котором только что изображался процесс переноса раздела с бэкапом базы. Вторые полсекунды я с наслаждением, граничащим с оргазмом, наслаждаюсь писком бесперебойника. Но спокойно чай попить мне все равно не удалось, потому что через две минуты бесперебойник сказал «кряк-кряк-кряяяяяяк-бзжжжжжжжжж», а в воздухе запахло горелым. Не успев сообразить, что к чему, с трудом в темноте выдёргиваю из бесперебойника все провода — треск прекращается.
Только наутро отпоенному корвалолом и слегка выспавшемуся мне улыбнулась удача: бэкап нашелся и на флэшке в тридцать два гига, на которой я таскал его домой. С конторы, продавшей мне бесперебойник, я таки срубил «компенсацию ущерба», но вот к своим нервам я с тех пор отношусь очень бережно.
Десять часов я потратил на отладку скрипта, который по непонятным мне причинам обрывал обработку данных и добавление их в MySQL после тридцати первых записей.
Только под полночь я вспомнил, что phpMyAdmin по умолчанию выводит данные по тридцать строк и нужно просто перелистнуть на следующую страницу.
В то время, когда я только начинал работать с MySQL, стукнуло мне в голову подучиться слепой печати — благо топтал клавиатуру я к тому времени уже лет шесть и большинство клавиш находил на автомате, лишь иногда бросая короткий взгляд для уточнения расположения «крайних» букв вроде «й» и «ъ».
Решено — сделано. Поставил себе знаменитое «Соло на клавиатуре» и развлекался в обеденное время. Набирать не глядя я научился, но возникла маленькая проблема — прежняя привычка печатать двумя-тремя пальцами порой приводила к тому, что я путал местами две ближайшие буквы в слове, нажимая клавишу раньше, чем следовало.
И вот сижу допоздна — надо составить последовательность команд, которая возьмет кусок из одной базы и перенесет сначала в «промежуточную», где подправит индексы, а затем отправит готовые данные по месту назначения. Пишу все это в файл, потому как делать подобное вручную уже надоело. Всё готово. На всякий случай сделал бэкап, запустил и отошёл от компа размять затекшие ноги.
Возвращаюсь и вижу в консоли кучу ошибок по поводу дублирования данных. Стал разбираться. Просмотрел свой файл — опечаток вроде нет. Полез ковырять временную базу — в некоторых таблицах индекс не обновился. Снова лезу в свой файл, отыскиваю нужное место... и сползаю под стол от хохота. Торопливость, помноженная на несовершенство навыка скоропечатания, сыграла со мной злую шутку: вместо «UPDATE» я умудрился напечатать «UPADET». Хорошо, что мускуль не понимает транслита!