Хотите легкого чтива под новый год? Вот крошечные истории про случаи из моей работы, или случаи, свидетелем которых я стал.
Свинья
Моя первая длительная работа была в фирме "Ниеншанц", царствие ей небесное. Она работала на самописной 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 расскажу... А пока почитайте предыдущую статью.
Комментарии (19)
red_baron_fiat
30.12.2021 12:23'$123.45' - это действительно удобно!
Сам так часто делаю, если чмсло 123,45 является "финишным" :)
qw1
30.12.2021 13:21+5Никогда не знаешь, какие завтра требования появятся к системе.
Заказчик вдруг заявит: а посчитайте мне суммы «финишных» значений в разрезах кварталов.
Что? Не суммируются? Но вот же они, мои финишные цифры, в чём проблема просуммировать?red_baron_fiat
30.12.2021 13:38Полностью согласен.
Под "финишниым" мне следовало уточнить, наверное, что это уже данные в "витрине" :)
DenisTrunin
30.12.2021 14:05Попутно дата-время хранилось не в datetime, а в двух колонках - одна дата в datetime с уcеченным временем, а время по моему в виде текста
Так а что в этом плохого? Т.е. ваш пример(найти все документы после какой-то даты и времени) наверное будет не очень оптимален, но как правило документы ищут просто по конкретной дате. В этом случае хранение даты будет как раз более оптимальным.
Хранение номеров документов в char является с лидирующими нулями, это как бы тоже типовое и оптимальное решение(т.е. номер накладной у вас будет что-то вроде Накл0001), нужно как раз для сортировки
Tzimie Автор
30.12.2021 14:46Там было ЦЕНТРИРОВАНИЕ, а не правое выравнивание, то есть, если пробел изображать нулем, то 5555 было 005555, а 44444 было 0044444
sshmakov
30.12.2021 15:58+3Жаловаться на "утечки памяти SQL", что он "занимает всю память" и перезапускать его все время
В те времена MS SQL имел багу в Notification Service, время от времени не завершалась какая-то транзакция от этого сервиса. В результате auto shrink не работал, база росла на диске, а процесс сервиса в памяти. Периодическое прибивание сервиса, но не самого SQL, спасало ситуацию.
polearnik
30.12.2021 16:01+1Насчет первой истории. Никогда не понимал в чем смысл тестовые записи пытатся делать прикольно-осмысленными. Пусть один клиент будет клиент1 а второй клиент2 и у них будут заказы заказ1 заказ2. по числам проще орьентироватся чем по записи что у свиньи должно быть хрюк и гав а у котяры мяу и хрюк
Rusty_Fox
SQL имеет весьма низкий порог вхождения и подкупает простотой, отсюда такие "перлы". А какой-нибудь Oracle за счёт мощного оптимизатора ещё и "прощает" подобное. До поры до времени.
Сам ни раз
писалвидел запросы, от которых волосы на спине начинают шевелиться.aegoroff
Сейчас все оптимизаторы примерно одинаковы, и вряд ли современный SQL сервер вообще уступает Ораклу, возможно даже наоборот. Оракл это тоже набор костылей - не знаю как сейчас а в версии 9 по моему, сделать запрос SELECT TOP 10 с условиями и сортировкой приходилось через одно место - деталей уже не помню но если надо могу поднять.
BugM
Это вы легаси проектов живущих на каком-нибудь mysql 5.5 еще не видели.
Их и мигрировать на более новый mysql сложно, и оптимизатора запросов там по сути нет. Вот и приходится поднимать пыльные архивы so и вспоминать как же построитель запросов работал в те годы. А работал он иногда очень неочевидным образом.
aegoroff
Видел и работал даже с версией и 3 и 4. Но вообще MySQL не любил никогда. В версии 3 кажется, некторые типы таблиц (ISAM кажется) даже не умели ACID нормально, а InnoDB были экспериментальными и дико тормозили на чтение. После 4 версии к счастью не сталкивался с этой СУБД более.
Rusty_Fox
Насколько я в курсе, MS SQL никогда не ругали за плохой оптимизатор, как раз наоборот, хвалили, как и Oracle.
Удивляться люди начинают, когда тащат "ораклячие" запросы например на PostgreSQL - на малых данных подвоха не заметно, зато на проде все внезапно встаёт колом. Хотя на Oracle работало. Такое видел, хотя Pg активно развивается, может, уже и такого не бывает.
В Oracle, если не изменяет память, версии так с 12-ой (которая 2013 года), добавили limit и offset, так что можно обойтись без извращений с rownum. 9-ка это что-то совсем уж старое.
aegoroff
Да все верно. А максимальная версия с которой я работал - была как раз 10-ка и там приходилось делать такой изврат.
Тут в общем то не зависит ничего от того куда чего тащат - тут важно фундаментальное понимание того как все работает, а не конкретный диалект СУБД. Если человек не понимает что такое индекс, что такое FULL SCAN, не умеет делать и читать планы построения запросов - везде будет плохо
mvv-rus
Смотря с какой стороны входить. Если со стороны «настольных» файловых БД (Clipper, FoxPro, Paradox и им подобных), да на Delphi, то MS SQL не прощал принятый в них стиль работы: «встать» на какую-нибудь запись, вывести ее на интерфейс и не спеша менять: MS SQL (точнее, его драйвер в BDE) вешал на эту запись блокировку, и у всех других, кто на нее натыкался, программа показывала песочные часы.
А вот Interbase, который в комплекте с Delpi шел, такое прощал — потому что поддерживал версионность, наверное в те времена — единственный: и в MS SQL некая поддержка версионности появилась сильно позже, и PostgreSQL тогда в версионность не умел…
Rusty_Fox
Под низким порогом вхождения имелась ввиду простота синтаксиса языка структурированных запросов, а вовсе не реализацию драйверов под конкретные СУБД в бородатых годах :)
Gallemar
Низкий порог в SQL эти иллюзия. Недавно разговаривал за жизнь с преподавателем курсов по DBA/SQL PostgreSQL - все кто приходил к нему "со знаниями SQL" очень быстро понимали, что весь объем их знаний рассказывается в первые три часа до обеда и не стоит ничего.
hard_sign
Не надо путать «порог вхождения» и «эффект Даннинга-Крюгера» :)
Rusty_Fox
Порог вхождения != знание языка в целом. Легкие запросы научиться писать легко, языковых конструкций и ключевых слов не много, синтаксис тривиальный. Сложности начинаются много позже.
Вашего преподавателя зовут
Том КайтМайкл Стоунбрейкер? Отдает каким-то бахвальством, честное слово.red_baron_fiat
Все зависит от того, какие таблицы образуют базу данных