Заметки

Мои мысли о жизни, работе и разных интересных штуках вокруг меня.

Показано: 0 · Страница

Diablo
22 сентября 2021 ·
Работа
Видеоигры

Хороший выпуск айтишного подкаста «Мы обречены» про выгорание разработчиков. Особых откровений нет, но что-то полезное для себя подчерпнуть можно. Очень понравилась аналогия с видеоиграми где-то ближе к середине:

Была такая игра — Diablo. Бегаешь ты там, RPG, всякие спеллы. У персонажа есть мана и здоровье, и когда у тебя маны на каст… Ха, звучу как задрот! Ну ладно. В общем, когда у тебя маны на каст не хватает, она у тебя начинает из здоровья браться.

— Доктор Кот

Про молоток и гвозди
15 сентября 2021 ·
Работа
Код с запашком

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

Вот есть у вас документ, да? В нём — несколько табличных частей. В каждой — поле для комментария. Делаете вы для этого документа печатную форму; если хотя бы в одной строке любой ТЧ есть комментарий — нужно использовать один шаблон, если комментариев нет — другой.

Задача примитивная, все мы миллион раз такое делали — ну, смотрим в выборку строк, натравливаем ПустаяСтрока() на нужное поле и грузим подходящий шаблон. Готово, можно пить кофе!

Однако, вместо короткого цикла я увидел это:

Ну то есть да, делаем матрешку из подзапросов, в самом нижнем из которых роемся в ТЧ (которые мы, напомню, только что выгребали для вывода на печатную форму). Ищем в них комментарии, если есть — ставим единичку. Нет? Нолик. Итог несколько раз группируем и возвращаем в скрипт.

Я сейчас даже не про нагрузку на СУБД (рискну предположить, что заметного эффекта этот трюк не дает — в конце концов, после отбора по ссылке выборка будет копеечной). Просто… Ну… Чекнуть выборку строк — пять строк кода. Понятных, простых, коротких, Сонару ругнуться негде. Как можно было родить вот это? Из большой любви к запросам?

А ведь что-то в этом духе и было, скорее всего. Я почти вижу его, этого кодера, который только что более-менее сносно освоил запросы и пребывает в перманентном восторге от новых возможностей. А когда в руках есть клёвый блестящий молоток, всё вокруг кажется гвоздями.

Без комментариев
8 сентября 2021 ·
Код с запашком

Сам не заметил, как бросил привычку педантично комментировать каждый метод, с которым приходится работать. Наверняка у этой практики есть какое-нибудь умное название, но мне нет дела, если честно. Я имею в виду стиль, когда описание добавляют к каждому осмысленному блоку кода:

Смысл тут простой: когда копаешься в каком-нибудь дремучем легаси и бегаешь туда-сюда между хаотично раскиданными процедурами на три экрана каждая — логику каждой из них держать в голове довольно трудно. Первая же чашка кофе всё смоет. Поэтому такие заметки на полях здорово ускоряют ориентацию на местности, и чем больше времени проходит между подходами к коду — тем заметнее эффект.

Однако в какой-то момент стало понятно, что это ноу-хау — просто костыль, подпирающий откровенно хреновый дизайн кода. Попалась тебе длинная процедура или функция — вздохни, сядь и нарежь толстяка на методы поменьше. Сэкономишь и время, и нервы, и в коде разберешься быстрее, и Сонар порадуешь.

Медленное оповещение
18 августа 2021 ·
Работа
Оптимизация

Твит

Прочитал этот твит и внезапно вспомнил случай из практики. Прилетает запрос от клиента — мол, 1С тормозит, сделайте что-нибудь. Уточняем: тормозит всё-таки не вся 1С, а конкретная операция.

База клиента — переписанная УТ, проблемная операция — из блока доработок. Внутри — множество многоэтажных запросов, возня с таблицами значений, какие-то невнятные вычисления и пачка серверных процедур по семьсот строк каждая. Копию базы снять нельзя, ТЖ недоступен, доступ к СУБД закрыт, доступ к счётчикам — тоже. Отладка на сервере 1С выключена, включить — не вариант.

Бардак, в общем. Как понять, где тут всё вязнет? Ладно, конфигурацию можно менять — уже неплохо. Вешаю на операцию замер: ну да, думает над чем-то пару минут. Отлично! Потираю ручки и сужаю область поиска: докидываю целый ворох замеров на самые подозрительные участки.

Результат любопытный: тормозов нет! Код не то чтобы летает, но о минутах и речи нет — с учетом сложности, расходы в пределах допустимого. Может, какая-то сериализация данных между клиентом и сервером? Тщательно выверяю код серверной процедуры — нет, никакой трансляции. Всё, что было на сервере, осталось на сервере.

Перехожу к клиентской части. Что тут может тормозить-то?.. Выглядел код, упрощая, как-то так:

Смотрел я на этот код, как баран, минут десять. В конце концов спросил коллегу и он рассказал удивительную вещь: оказывается, Оповестить() не просто рассылает оповещения во все открытые формы, а ждёт, когда в них завершится обработчик оповещения.

Я знатно офигел, полез проверять и в конце концов наткнулся на форму, которая ловила событие выполнение операции и подрывалась обновлять свои динамические списки. Запрос в одном из них и давал тормоза (там подзапрос к подзапросу к подзапросу и ворох соединений «через точку» — в общем, дальше не интересно).

Такая вот яломиште :-) Оповещайте с осторожностью!

Умер Павел Чистов
1 августа 2021 ·

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

Никита Грызлов, Илья Леонтьев и Сергей Горшенин собирают деньги для помощи семье Павла. Кроме того, номер карты его вдовы есть в конце некролога по ссылке выше.

Берегите себя, пожалуйста.

Поиск долгих запросов с помощью Python
18 июля 2021 ·
Bash
Python

Выложил скрипт на Python для поиска длительных запросов в ТЖ 1С. Накатал его в приступе отчаяния: никак не мог понять, почему мой верный баш для одного из запросов выдаёт среднее время выполнения больше максимального.

Как выяснилось, проблема была в gawk. Для некоторых событий ТЖ эта утилита не могла определить длительность: пыталась преобразовать строку в число, фейлилась и… Нет, что вы! Конечно, не кидалась исключением! Просто невозмутимо считала эти строки за ноль и ехала дальше.

Патч, кстати, вышел ещё глупее проблемы: я просто сделал явное преобразование строки в число, и всё заработало как надо. Чем, блин, явное преобразование в мире gawk'а отличается от неявного? И, главное, почему?

Короче, цирк уехал, новый скрипт остался. Впрочем, он бережнее расходует память и процессор: в скрипте на баше для расчёта количества выполнений запроса, суммарного времени выполнения и максимального времени одного выполнения я использовал три коллекции, у каждой из которых ключом был текст запроса и его контекст. Соответственно, все три нужно было обновлять и держать в памяти.

Это вполне рабочая тактика, пока входящий поток не переваливает за сотни тысяч элементов: где-то тут мы начинаем терять гигабайты ОЗУ на хранении коллекций и прорву времени процессора на поиске в них. Новый скрипт попрямее: коллекция одна, но хранит всe данные по каждому запросу.

Почему не баш?
3 июля 2021 ·
Bash
Python

В прошлой заметке я говорил о задачах, для решения которых баш — идеальный инструмент: минимум ограничений, простые условия — и оговорился, что иногда он вообще не справляется.

Чтобы не быть голословным, давайте пример из практики. Есть, скажем, порядка семидесяти гигабайт логов ТЖ 1С, по которым нужно построить топ пояснений к исключениям — от самых частотных к менее частотным.

Плёвое дело, верно? Выгребаем EXCP, извлекаем Descr, считаем повторения. Даже нужный скрипт я как-то уже писал. Запускаю, терпеливо жду…

Знаете, сколько понадобилось времени? Я тоже нет: после того, как скрипт проработал сутки, я его вырубил и полез разбираться, в чём проблема. Затык возник где-то в скрипте gawk'а: именно она активно нагружала процессор (если не считать cat'а, которая время от времени читала очередную порцию данных).

Процессы

Беда, беда, огорчение! В общем, я подумал и переписал этот скрипт на Питоне. Новая версия отработала за 15 минут и дала мне:

  1. Топ пояснений по событиям исключений;
  2. Скрипт, который можно прочитать через полгода без помощи гугла;
  3. Уверенность, что я могу добавить в скрипт два-три условия и не вызвать Сатану случайным сочетанием операторов и ключей.

Конечно, я мог оптимизировать версию на баше. Вероятно, тормозит поиск в массиве — время, необходимое для поиска пояснения в массиве уже зафиксированных пояснений, линейно растет с увеличением размера массива. Можно, например, попробовать изменить подход к сбору данных — gawk'ом только извлекать сами пояснения, а результат сбора передать в тандем sort & uniq.

Однако это уже отчётливо отдаёт мемасом про буханку хлеба: из неё, конечно, можно сделать троллейбус, просто не очень понятно — зачем? Камон, мне бы проблему решить. А Питон с ней уже справился на твердую пятёрку, чем сэкономил мне кучу времени и нервов.

Собственно, к этому я вел. Родовые травмы баша понятны и нередко приемлемы, плюсы — приятны и очевидны, но при работе с ним вопрос иногда встает так: cтоит ли только ради того, чтобы получить решение именно на баше, потратить часа два на возню с утилитами, параметрами, мануалами и постами на Stack Overflow?

Твит

Вот поэтому не баш, да.

UPD: Хорошая заметка Ивана Гришаева на ту же тему.

Почему баш?
23 июня 2021 ·
Bash
Python

Периодически вижу вопросы коллег: а что, 1С всё ещё носится с башем, да? А чё не пайтон-то? Или павершелл, на худой конец? Вот чудаки!

Да, баш не родной для Windows (которая, напротив, родная для 1С) и притащить его туда — отдельная история; да, при усложнении задачи читаемость скрипта падает по экспоненте; да, с некоторыми задачами баш просто не справляется.

Однако главный плюс баша в том, что для многих задач по анализу ТЖ 1С он — самое простое и быстрое решение. Как старая отвертка, которой ещё дед пользовался. Она всегда под рукой — пусть поцарапанная, с зазубринами и слегка корявая, но всё еще прекрасно работает.

Пример? Допустим, нужно выгрести из ТЖ исключения; простоты ради договоримся, что достаточно первой строки каждого события. Получим примерно такой скрипт на пайтоне.

Скажете, его можно легко сократить вдвое? А то и втрое. В конце концов, мы решаем локальную задачу. Возня с читаемостью и предсказуемостью тут ни к чему.

Согласен! Но давайте сначала решим ту же задачу на баше:

grep -r --include "*.log" ',EXCP,' > result.txt

Вот почему баш.

Метаданные не найдены
8 июня 2021 ·

Метаданные не найдены

Думаю, с этой ошибкой мало кто сталкивался. Для этого, во-первых, нужно работать со встроенной в платформу историей данных, а она не больно-то популярна: кто-то привязан к БСП (она пока использует привычное всем версионирование на регистрах сведений), кому-то не нравится реализация — там и правда не всё гладко с точки зрения производительности.

Во-вторых, нужно сделать так: выключить историю данных для объекта метаданных, а потом грохнуть накопленные версии объектов до того, как новые изменения объекта перекочуют из буфера в основную таблицу.

В двух словах о том, как вообще работает история данных. По дефолту она выключена, и достаточно привилегированный пользователь может включить её для нужных ему объектов — констант, справочников, документов и так далее. После этого при изменении данных в этих объектах платформа будет фиксировать, что именно меняется. Делает она это в два этапа: сначала — относительно быстрая запись в промежуточный буфер (таблицу _DataHistoryQueue0); потом, при вызове метода ОбновитьИсторию(), информация мигрирует в основное хранилище версий (таблицу _DataHistoryVersions) и становится доступна в интерфейсе приложения.

Обновление истории можно делать сразу при записи, но для сокращения транзакции его обычно выносят в регламентное задание. В итоге миграция данных из буфера в основную таблицу происходит с некоторой периодичностью: например, раз в пять минут. Так вот, если между изменением данных объекта и обновлением истории данных выключить историю объекта и удалить его версии — метод ОбновитьИсторию() выкинет исключение: он попытается переместить изменения из буфера в основную таблицу, но не сможет привязать их к уже накопленным данным.

Для наглядности — рабочий код, воспроизводящий проблему для справочника Items на платформе 8.3.17.1989. Можете подставить любой другой объект, с которым работает история данных — разницы нет.

Как избежать этой ошибки? Ну, очевидно: метод ОбновитьИсторию() нужно вызывать непосредственно перед тем, как отключать историю для объекта. Лучше всего делать это в период, когда пользователи с системой не работают: есть риск, что между обновлением истории и её выключением вклинятся чьи-то транзакции, которые спровоцируют ту же проблему. Для гарантии можно использовать монопольный режим.

Ещё в голову приходит исключительная блокировка на таблицу объекта, но документация не советует вызывать метод ОбновитьИсторию() внутри транзакций — так что тут я не уверен.

Как исправить эту ошибку? Включите историю данных для проблемного объекта, обновите историю и выключите её обратно. Выйдите, так сказать, из класса и зайдите нормально.

Скрипт для синхронизации c NAS
7 июня 2021 ·
Готово
Python
Рабочее место

Выложил на GitHub скрипт на Python, который я использую для синхронизации файлов между своим компьютером и домашним NAS'ом. У меня стоит Synology DS220j; с ним так-то идет целый вагон софта и в том числе утилита, которая умеет гонять файлы туда-сюда по расписанию. Однако сделана она, похоже, чисто для галочки: программа принялась глючить ещё на этапе настройки, после чего доверие к ней я потерял.

В общем, какое-то время я помучался с решениями конкурентов и в итоге вернулся к привычному rclone, с которым было всего две проблемы. Во-первых, нельзя нормально соединиться с SMB-шарой: да, логин и пароль можно сохранить в Windows и rclone будет их использовать, но они будут слетать при каждом удобном случае. Я вышел из положения, подключив шару как внешний диск.

Во-вторых, файлов и папок для синхронизации у меня оказалось много: директория здесь, директория там, конфиг оттуда, профиль отсюда… Чтобы не плодить лапшу, я накатал простой скрипт, который берет из конфига источники и приемники, а потом для каждого вызывает rclone по одному и тому же шаблону.

Как готовиться к 1С:Эксперту
25 мая 2021 ·
Готово

В середине мая я сдал экзамен на статус эксперта в 1С по технологическим вопросам крупных внедрений. Подготовка вышла долгая, почти два года — так что я чертовски рад, что наконец-то справился.

В сети есть море материала про этот экзамен и связанные с ним темы — начиная с курса Виктора Богачева и заканчивая, не знаю, релевантным чатом в Телеграме. То есть вопрос из заголовка заметки обычно не стоит. Но я хочу написать о паре психологических заморочек, к которым лучше быть готовым заранее и о которых обычно не вспоминают.

Нехватка дофамина

Этот экзамен — сложный. Подготовка может затянуться, как и сдача: очень вероятно, что потребуется несколько попыток. Я справился со второго раза, но у людей выходит по-всякому — среди моих знакомых есть те, кто сдал с третьего, пятого или даже восьмого захода.

То есть может получиться так, что вы раз за разом будете сильно вкладываться, а результата не получать. Через какое-то время ваш мозг решит, что этой задачи надо избегать: какая-то она провальная, бесполезная и вызывает неприятные ощущения. Как это повлияет на конечную цель, догадаться легко.

Поэтому к подготовке лучше подходить как к долгому и рискованному проекту: разбавлять её короткими и, главное, успешными задачами. Для мозга нет существенной разницы между большим и маленьким успехом, и вернуться к основному проекту будет проще.

Например, я для отвлечения катал скрипты для домашней автоматизации — генератор статики для этого сайта, органайзер на текстовых файлах, обвязку для домашнего NAS'а и тому подобные штуки, до которых раньше никак руки не доходили. Подойдут любые задачи — включая те, что с айтишечкой вообще не связаны. Почистить слив в ванной? Отличная идея!

Нехватка памяти

Если вы не работаете с проблемами производительности 1С каждый день, этот экзамен — очень ресурсоемкий контекст. Вы будете держать в голове массу вспомогательных данных, которые обычно берете из документации: флаги трассировки и имена динамических представлений Microsoft SQL Server, настройки PostgreSQL и рекомендации по их заполнению, перечень стандартных индексов платформы и так далее, и тому подобное. Во-о-от такенная куча информации! (показывает руками, какая)

Между тем, наш мозг при работе с большими объёмами данных порой крепко напоминает СУБД, работающую с переполненным буферным кэшем. Другими словами: всё, что не нужно в данный момент, будет выгружено из памяти. Готовьтесь забывать самые неожиданные вещи: номер своей квартиры, кличку соседской собаки, день рождения жены — и это ещё не самые диковатые последствия. Я, пока готовился, чуствовал сильное духовное родство с Джонни Мнемоником — персонажем старого-престарого киберпанка, который загрузил себе в мозги столько данных, что чуть не отбросил коньки :-)

Не надо так

Выхода тут мне видится два, оба довольно очевидные.

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

Во-вторых — старайтесь строить ассоциативные цепочки для наиболее заковыристых штук. Взять, например, баш! Название утилиты sed проще запомнить, если знать, что это сокращение от Stream EDitor. Утилита cat называется так, потому что concatenate, а не потому что кошка, но если вам проще запомнить второй вариант — так и делайте. Почему нет?

Или, скажем, маркер последовательности байтов. \xef\xbb\xbf, ага. Его я намертво запомнил — только не смейтесь — через абсолютно иррелевантную фразу «Elf Friend BB Best Fight». Понятия не имею, почему моя голова работает через такую жо такие заковыристые интерфейсы, но жаловаться я не собираюсь. Главное — отыскать их!

Новый скрипт поиска долгих запросов
26 апреля 2021 ·
Bash
Готово

Обновил скрипт поиска долгих запросов в технологическом журнале платформы. Ранняя версия содержала серьёзный косяк: она старательно группировала DBMSSQL по Sql и Content, но игнорировала случаи, в которых поле Sql отсутствовало (для DBMSSQL это не то чтобы норма, но встречается).

Ну и код слегка причесал, чтобы два раза не вставать: добавил разметку и комментарии, а часть логики gawk'а вынес из основного тела в функции. Да, скрипт стал смотреться длиннее, чем он есть на самом деле, зато читать его стало куда проще.

Мне вообще, по-чеснаку, непонятна причина, по которой ветераны баша трамбуют всю логику в две-три строки: язык и так-то не блещет читаемостью (в телеграм-канале Никиты Прокопова есть отличный текст на эту тему), а при виде страницы конвейеров без единого перевода строки вообще хочется молча выйти в окно.

Пучок скриптов
24 апреля 2021 ·
Bash
Готово

Выложил на GitHub ещё несколько скриптов для разбора технологического журнала платформы, которые написал за последнее время:

  • Частотные события. Группирует события по наименованию, считает количество воспроизведений для каждого и выводит в порядке убывания — от наиболее частотного к наименее частотному. Практического применения у этого скрипта, скорее, нет; просто фиксировал для себя, какой процесс кластера какие события пишет.
  • Описания исключений. Группирует EXCP по полю Name; для каждого наименования выводит варианты значений поля Description, которые были у исключений с таким наименованием. С помощью этого скрипта можно составить примерную картину: какие исключения действительно проблема, а какие — просто белый шум, который можно игнорировать и, например, закинуть в фильтры Кибаны.
  • Блокировки по ID соединения и области. Удобен для поиска виновника таймаута на управляемых блокировках: скрипт выгребает из ТЖ все TLOCK'и по конкретной области от конкретного соединения, а потом выстраивает их в хронологическом порядке.
SKUUUID в своем глазу
22 февраля 2021 ·
Код с запашком

Пару недель назад Александр Кунташов у себя на канале запостил забавный скрин перечисления из Библиотеки Электронных Документов, создателей которого откровенно манили длинные аббревиатуры. Я бодро острил на тему родства ИППДОИПУПДУКД'а и московского ГНУВНИВИПФИТ'а, а потом увидел в собственном коде вот эту красотку:

SKUUUID

Ещё не вполне рука маэстро, конечно, но движение определенно в том же направлении. Вспомнилась притча про сучок в чужом глазу и суковатое бревно — в своём :-)

Проблема с литералом даты при пересчете итогов
6 февраля 2021 ·

Итак, в ходе рутинного пересчета итогов из Конфигуратора мы неожиданно получили ошибку «номер года в литерале типа дата превышает 3999». Это значит, где-то в базе есть (или пытается появиться) дата больше, чем предельно допустимая с точки зрения 1С (31.12.3999 23:59:59).

Исключение

Ладно, что с этим делать?

Главное — выйти на конкретную таблицу с проблемными датами. Ошибка возникла при пересчете итогов, так что очевидно: искать нужно в регистрах. Открываем стандартную обработку управления итогами, делаем пересчет и получаем имя регистра, на котором спотыкается платформа.

Другой, более методологически правильный подход — настроить сбор ТЖ (SDBL, EXCP и EXCPCNTX) и получить примерно такой лог. Ищем в нём событие EXCP (исключение), а непосредственно перед ним — событие SDBL (SQL-запрос в терминах платформы). Этот запрос — причина сбоя; в его тексте видим имя нужной нам таблицы (AccumRgTn11530). Имя объекта конфигурации для неё можно вытащить любой обработкой, построенной на методе ПолучитьСтруктуруХраненияБазыДанных().

В общем, так или иначе мы получим имя регистра. Открываем его форму и простой сортировкой по периоду выходим на проблемные движения. Нужно проанализировать документы, которые их сделали, устранить причину ошибки и перепровести документы. Если после этого проблема с пересчетом останется — это либо не единственная таблица с проблемными датами (ищем дальше), либо эти даты успели засесть где-то ещё, кроме таблицы движений.

Например, у меня был случай, когда после исправления движений записи с некорректными датами сохранялись в таблице оборотов. Средствами платформы их удалить было нельзя, но размер базы позволял играться с реструктуризацией. Я выкинул следующий финт: отключил признак «Использование в итогах» для всех измерений регистра и применил изменения; потом вернул признак на место и пересчитал итоги. В итоге таблица оборотов регистра была физически удалена, а потом создана и наполнена заново — уже без дат на много веков вперёд.

В крайнем случае можно было удалить проблемные записи с помощью прямых SQL-запросов (DELETE или даже TRUNCATE). Но это, во-первых, нарушает лицензионное соглашение с разработчиками платформы, а во вторых — опасно (по неосторожности можно удалить что-то важное и не заметить). Так что не советую, э-э, повторять в домашних условиях :-)

Определение видимости объекта
17 января 2021 ·

В платформе сразу несколько механик решает, видит пользователь некий объект метаданных или нет. Одна из них — функциональные опции. Если вы раньше не имели с ними дела, в двух словах дела обстоят так: объект можно добавить в состав опции, которая внутри конкретной базы может как быть активной (и видимой пользователям), так и неактивной (и, соответственно, скрытой). Объект можно засунуть в несколько опций сразу (и тогда он отображается, если активна хотя бы одна из них) или не включать вообще никуда (и тогда пользователи его видят в любом случае).

Так вот, помню, лет пять назад я искал способ понять из кода — видит пользователь объект или нет? Чисто с точки зрения функциональных опций. Тогда я почему-то не нашел решения, а ведь оно до смешного простое; вот, например, функция ровно для этого. Логика:

  1. Перебираем опции и ищем объект в составе каждой из них.
  2. Если объект есть в составе опции, проверяем: опция активна? Если да — значит, пользователь видит объект.
  3. Если объект не включен ни в одну опцию — тоже видит.

Конечно, результаты такого анализа как минимум нужно кэшировать (хотя бы из-за запроса в цикле), но в остальном он вполне адекватен. Никак не возьму в толк, почему я тогда не написал что-то похожее? Ох, надеюсь, спустя следующие пять лет мои нынешние занозы в заднице тоже будут отлетать на раз-два-три.

Рекурсивный поиск по файлам
14 января 2021 ·
Bash

Время назад я примеривался к поискам уязвимостей в коде скриптами на bash (звучит грозно, но это просто рекурсивный поиск текста с помощью регулярных выражений). Скрипты-то я тогда написал, но, как сегодня понял — несколько… Ректально, кхм. Для решения хватает одного egrep! То есть из связки find, xargs и egrep можно выкинуть два компонента из трех.

Например, сегодня у нас возникла проблема: конфигурация перестала собираться в последнем релизе EDT. Подозрение пало на битые GUID — ссылки на объекты метаданных, удаленные из конфигурации. Платформа не всегда справляется с их вычисткой после того, как удалит сами объекты; я уже пару раз писал про это (например, здесь или вот тут).

В общем, мы решили порыться в выгрузке конфигурации — найти GUID'ы и оценить, все ли они находятся там, где положено. Общее решение — одна-единственная команда:

egrep -rn '.{8}-.{4}-.{4}-.{4}-.{12}' dump

Ключ r включает рекурсивный поиск, ключ n — заставляет утилиту пристегнуть к найденной строке не только имя файла, в котором найдена строка, но и номер самой строки. Последний параметр, dump — имя директории, где нужно искать.

Регулярку можно сделать точнее, но и такой за глаза хватает. Что до ложных срабатываний (то есть GUID, которые не являются битыми ссылками) — их легко отсеять через пайп. Например, скрипт ниже не будет выводить строки с GUID, в которых есть подстрока «uuid»:

egrep -rn '.{8}-.{4}-.{4}-.{4}-.{12}' dump | grep -v 'uuid'
Старый добрый DATETIME
11 ноября 2020 ·
MS SQL

Порылся в сети по поводу типов дат в MS SQL Server и в целом вопроса «почему 1С до сих пор носится со своим смещением» больше не имею. Люди пишут о целой пачке проблем с DATETIME2:

  1. Недоступна базовая математика. Без дополнительных финтов ушами не выйдет посчитать разницу между двумя датами, прибавить к дате день и так далее.
  2. Стандартные функции по-прежнему возвращают старый добрый DATETIME (например, DATEADD). Если данные хранятся в DATETIME2 — потребуется конвертация.
  3. Поля с этим типом неважно индексируются, так как каждое значение DATETIME2 хранится задом наперед (сначала время, потом дата). В итоге СУБД промахивается с оценкой количества строк, которое может вернуть запрос, и строит для него неэффективный план выполнения.

Подробнее о всем этом можно прочитать на Towards Data Science или, например, на SQL Server Central.

Смещение дат в 1С
10 ноября 2020 ·
MS SQL

В MS SQL Server поля DATETIME не могут хранить даты раньше 1753-го года. Например, если попытаться записать в базу 01.01.0001 — получим ругань на out-of-range value. Я считал это забавным для такой почтенной СУБД рудиментом, пока случайно не наткнулся на причину.

Если вкратце, в 1752-м году Великобритания внедрила у себя Григорианский календарь, и в процессе у них из летосчисления пропало одиннадцать дней. Это породило проблему: вот хочет юзер посчитать разницу в днях между 1653-м и 1753-м годом — что делать будем? Учтем потеряшек? Проигнорируем? Сделаем какие-то хинты или настройки?

Видимо, чтобы не городить неоднозначные механизмы, разработчики СУБД решили вопрос радикально — усечением доступного диапазона дат. А для тех, для кого это проблема, есть DATETIME2, который никаких ограничений не имеет.

Что касается 1С, то изначально платформа использовала DATETIME, а чтобы не иметь головной боли с хранением дат раньше 1753-го года — придумала специальный костыль. В двух словах: когда платформа пишет даты в БД, то тихой сапой прибавляет к каждой две тысячи лет, а когда читает — вычитает обратно. То есть в 1С пользователь видит 01.01.2000, а в БД на самом деле хранится 01.01.4000.

Любопытно, почему 1C до сих пор не выкинула эту штуку? Сейчас платформа использует DATETIME2 и фокус по смещением в общем-то не нужен. Конечно, тут могут быть какие-то подводные камни или просто разумная осторожность, но среди разработчиков самой СУБД сомнений не заметно:

Your great great great great great great great grandfather should upgrade to SQL Server 2008 and use the DateTime2 data type, which supports dates in the range: 0001-01-01 through 9999-12-31.

Joe Stefanelli (SQL Server developer)

Возможно, это просто на дне приоритетов. Добавление и удаление двух тысяч лет для каждой даты, конечно, увеличивает нагрузку на оборудование, но на фоне остального она теряется.

Халк удалять!
9 ноября 2020 ·
PostgreSQL

На курсе по PostgreSQL узнал смешную деталь: в 10-й версии СУБД разработчики переименовали папку pg_xlog (журналы предзаписи) в pg_wal, а папку pg_clog (статусы транзакций) — в pg_xact.

Знаете, почему? Из-за не слишком опытных, но уже достаточно смелых администраторов, которые триггерились на слово «log» в названии папки. Мол, мне нужно место на диске освободить, а тут СУБД забила всё своими дурацкими логами. Некогда разбираться, rm -rf их и порядок!

В общем, в трубу одновременно вылетала и защита работы с данными в буферном кэше, и многоверсионность. После чего кластер умирал в муках. Свободного места на диске получалось много, но радоваться этому, боюсь, приходилось недолго :-)