Хотите легкого чтива под новый год? Вот крошечные истории про случаи из моей работы, или случаи, свидетелем которых я стал.
Свинья
Моя первая длительная работа была в фирме "Ниеншанц", царствие ей небесное. Она работала на самописной ERP, которую писали мы - группа из 3-4 человек. Это были 90е годы, мы варились в собственном соку и не слышали про QA. То есть, девелоперская версия кода у нас крутилась отдельно, а база была одна-единственная, она же PROD. В горячие времена мы могли испечь и выкатить несколько релизов в день, без всяких новомодных DevOps, CD, CI.
Вскоре после моего ухода одного из моих коллег нашли рыдающим на клавиатуре. Он повторял одно слово - свинья. К счастью, рыдал он от смеха. Отлаживаясь на PROD, я заводил документы и, чтобы не пересекаться с реальными документами, заводил фиктивных клиентов, товары и услуги.
Так возникла доверенность на некую Свинью, которая умудрилась получить доверенность на Хрюкание. Аудиторы тоже очень удивлялись. Но они чаще плакали.
О форматах данных
Немного повторюсь, эта история из моей работы в Америке, где я работал, в том числе, в стартапе под названием Softlock.
Как образовалась там вакансия DBA? Взлет Softlock совпал с продажей книги Стивена Кинга "Riding the bullet" в формате PDF за символический 1 доллар через Softlock. В час X должна пойти реклама. Разумеется, за несколько недель до часа X программисты днюют и ночуют на работе. За пять минут до рекламы DBA вносит самое последнее изменение. В команде DELETE он забывает WHERE и удаляет все данные в важной таблице. Бэкап! кричит он. Поздно, мы в эфире - говорят ему. Как идут продажи? спрашивают менеджеры.
Короче, кое что им удалось подправить, наделав кучу костылей. DBA все исправил, но, не выдержав позора, покинул фирму. Я же разгребал его костыли вместе с коллегами из страны, где очень любят петь и танцевать. Один коллега, например, хранил суммы таблице varchar() примерно так: '$123.45'. Я спросил его - зачем? Он пояснил, что это очень удобно, когда сумму отображаешь для пользователя, то не надо делать никаких преобразований.
Шоу для французов
Во Франции вскоре после начала работы меня спросили, насколько я могу ускорить их систему. Я решил выглядеть профессионально, не говорить сразу - в 10 раз, а сказал - процентов на 30-40%. В итоге я ускорил систему более чем в 10 раз - у них для списков не было даже элементарного pagination, но это другая история.
Дело было в пятницу и французы что-то отмечали. Меня спросили, правда ли русские могут пить водку, как показывают в фильмах? Я налил водку в пластиковый стаканчик и продемонстрировал. О, сейчас других позовем - не уходи! И я показал еще и еще.
А потом на меня посмотрели и сказали - "он же сам домой не дойдет". Посадили в машину моего шефа, меня укачало, и я ее облевал. До сих пор стыдно. Зато меня зауважали как специалиста.
Динозавры
Время от времени мне доводилось консультировать разных клиентов. Среди них тогда, в 2000х, еще встречались "динозавры". Я их узнавал по двум характерным вещам:
-
Поставить базу в FULL RECOVERY, не делать бэкапов, дождаться, когда LDF файл станет 100Gb, спросить "почему база так быстро растет"
-
Жаловаться на "утечки памяти SQL", что он "занимает всю память" и перезапускать его все время
Сейчас таких уже почти не встречается, но тогда это были два самых частых вопроса
Рулетка
У одного клиента стояла задача читать из таблицы случайную запись. Это не причуда - это был сайт с тестами, и вопросы надо было рандомизировать. Это делалось замечательным кодом:
SELECT TOP 1 * FROM table ORDER BY newid()
Работало это прекрасно, вот только медленно: сервер должен сгенерить newid() для всех записей таблицы и потом их упорядочить. Как ни элегантно было это решение синтаксически, мне пришлось от него избавиться.
Заветы Oracle
В одной конторе люди, которые танцуют и поют, очевидно, пришли из Oracle (да какая им разница на чем лабать код?). После вставки записи им надо было получить @@IDENTITY. Они пишут
SELECT @@IDENTITY
и дальше их клинит. Потому что в Oracle надо обязательно писать FROM, для этого есть даже специальная табличка DUAL. Первое что им приходит в голову - указать имя самой таблицы, допустим, это была таблица FACTS:
SELECT @@IDENTITY FROM FACTS
В этом случае значение IDENTITY копируется столько раз, сколько записей в таблице. Люди, которые танцуют и поют "элегантно" заметают это под ковер:
SELECT DISTINCT @@IDENTITY FROM FACTS
И все замечательно работает... Некоторое время. Пока записей не становится много, и все встает колом. SQL генерит огромный dataset каждый раз, сортирует его и делает distinct.
Параноя
С этим столкнулся мой коллега. Фирма - в России. Некая самописка плохо поддерживаемая. Тормоза. Быстрый анализ показывает, что очень помогут несколько индексов. Индексы создаются и... система отказывается стартовать!
Анализ SQL profiler показывает код, который при старте системы считывает все из sysobjects, sysindexes, syscolumns, и параноидально вычисляет checksums всего, чтобы не дай бог не изменили колонку или таблицу. Ну и индексы в том числе.
Представляю как, наверное, девелопер расчесал свое ЧСВ этим кодом!
Suicide jobs
Нет, это не о камикадзе. Очень интересная система, опять написаная друзьями с юга, имела функциональность асинхронных рассчетов на SQL. Тут без сарказма - ребята молодцы, создавали SQL agent jobs, которые выполняли расчеты и потом выпиливались (не ребята, а SQL jobs) - да, в SQL job может удалить саму себя!
Все это работало, но когда количество порождений jobs превысило 3-5 в секунду, пошли deadlocks со стороны SQL agent - он просто не рассчитан на такой стиль использования. Я все это переписал на статические асинхронные "worker threads"
Безумная сортировка
Очередная тормозящая система. Порядковые номера документов хранятся почему-то в char(9) центрированными - да, центрированными! То есть '127' будет выглядеть как <три пробела>127<еще три пробела подразумеваются>. А значит, на лету:
ORDER BY convert(int,ltrim(Docnum))
со всеми сопутствующими тормозами. Попутно дата-время хранилось не в datetime, а в двух колонках - одна дата в datetime с уcеченным временем, а время по моему в виде текста. Чтобы найти документ после какого-то точного времени надо писать:
(DATE>'дата' OR (DATE='дата' AND TIME>'время')
со всем радостным, что приносит для поиска OR. Тот, кто ко мне обратился, говорил, что систему писали голланцы (видимо, под веществами)
И еще абсолютно убойный случай
Один раз сотрудник сотрудник нашей компании (назовем этого парня <NDA>), где я сейчас работаю, умудрился <NDA>, да так, что <NDA>, а потом еще <NDA>, в итоге его самого <NDA>, а потом догнали, и еще <NDA> по самые <NDA>. Кто работает у нас, разумеется, знает эту историю (совсем как "анекдот номер 187... ну нельзя же при женщинах"), а я ее рассказать сейчас не могу.
Может лет через 10 расскажу... А пока почитайте предыдущую статью.
Автор: Дмитрий EvilDBA