"На глаз похоже" - не приёмка: сверка отчётов контрольной суммой
Иван Недомолков · Жарияланды: · Жаңартылды:
Любая оптимизация отчёта заканчивается одним и тем же разговором. Исполнитель: “стало в три раза быстрее”. Бухгалтер: “а цифры точно те же?” И дальше два пути: либо полчаса вглядываться в две простыни на глаз (“вроде сходится”), либо предъявить доказательство, с которым не поспоришь. Мы ходим вторым путём: результат “до” и “после” должен совпасть побайтово, и это проверяет машина, а не глаза.
Идея: контрольная сумма вместо глаз
Методика умещается в три строчки:
- Выгружаем результат отчёта “до” оптимизации в файл.
- Выгружаем результат “после” - на тех же данных и параметрах.
- Считаем SHA-256 обеих выгрузок. Совпал - отчёты идентичны. Не совпал - ищем, где разошлось.
Хеш-функция устроена так, что изменение хотя бы одного байта меняет сумму целиком. Совпавший SHA-256 - это математическое доказательство идентичности, а не мнение. Спор “а вдруг где-то в тридцатой странице копейка уехала” закрывается до его начала.
Дьявол в нормализации
Наивная сверка “выгрузил как есть и захешировал” почти всегда даст ложное расхождение, как и сверка остатков 1С и WMS с разными формулами по двум сторонам. Прежде чем хешировать, выгрузку надо нормализовать - привести к канонической форме, устранив всё, что легально может отличаться:
- Порядок строк. Если в запросе нет полного явного
УПОРЯДОЧИТЬ ПО, СУБД вправе вернуть строки в любом порядке - и после смены плана запроса порядок изменится. Либо жёсткая сортировка в самом отчёте, либо сортировка выгрузки перед хешированием. - Форматы чисел и дат. “1 234,50” и “1234.5” - одно значение и разные байты. Выгружайте сырые значения в фиксированном машинном формате, а не отформатированное представление.
- Служебные поля. Время формирования, имя пользователя, номер версии в шапке - вырезать: они меняются законно.
- Кодировка и переводы строк. Зафиксировать (UTF-8, LF) - иначе сверка между машинами начнёт врать.
- Плавающая точка. Если в отчёте есть агрегаты по Числу с плавающей точкой, порядок суммирования может менять последние знаки. Лечится округлением до значащей точности при выгрузке - и это надо решить до снятия эталона.
Правило простое: нормализация должна убирать представление и сохранять содержание.
Как это встроено в процесс оптимизации
На проекте оптимизации розничной сети (шесть тяжёлых отчётов, ускорение −22…−42 %) регламент был жёстким - совпадение контрольной суммы было условием деплоя:
- До любых правок: снимаем эталонную выгрузку отчёта на зафиксированном наборе параметров и периодов. Несколько вариантов параметров - краевые случаи тоже.
- Правим запрос/код.
- Снимаем выгрузку “после” на тех же параметрах, нормализуем, сравниваем SHA-256.
- Совпало по всем наборам - изменение едет на прод. Не совпало - разбираемся: иногда это наша ошибка, а иногда… находка.
Приятный побочный эффект: сверка находит старые баги
Расхождение хеша не всегда означает, что оптимизация что-то сломала. Пару раз оно означало, что старый отчёт считал неправильно: дважды применённый фильтр, потерянные строки из-за внутреннего соединения там, где нужно левое. Тогда разговор с заказчиком меняется: “мы ускорили отчёт и заодно нашли, что он три года занижал итог по одному складу - вот строки”. Это неприятная, но самая полезная минута проекта.
И обратная честность: часть отчётов после разбора мы не тронули - узкое место было не в запросе, и переписывание дало бы только строчку в отчёте о проделанной работе. Сверка дисциплинирует и исполнителя: не можешь доказать идентичность - не лезь.
Границы применимости
- Отчёты с настоящей недетерминированностью - случайные выборки, зависимость от текущего момента (“остатки на сейчас”) - сверяются только на замороженной копии данных.
- Изменение самой формы отчёта (добавили колонку) - хеш обязан не совпасть; сверка работает для рефакторинга “то же самое, но быстрее”, а не для доработок функциональности.
- Огромные выгрузки - гигабайтные результаты дольше выгружать, чем хешировать; для регулярной сверки берите репрезентативные параметры, а не “всё за всю историю”.
- Отчёты, где порядок строк не задан и меняется вместе с планом запроса - побайтовая сверка на них отваливается на тех самых правках, ради которых её заводили. Там вместо файла сравнивается слепок результата из трёх частей: число строк, сумма числовых ячеек и хеш по нормализованным строкам, отсортированным как строки.
И главная оговорка, из-за которой приёмку считают сделанной, когда она сделана наполовину. Совпавший хеш доказывает, что вы ничего не сломали. Он не говорит ни слова о том, починили ли вы что-нибудь: у нас минус 13 % на переписанном отчёте оказались шумом нагрузки прода и исчезли при перепроверке чередованием.
Тот же принцип - не только для отчётов
Побайтовая сверка - универсальный язык доказательств в задачах “изменили внутренности, поведение должно остаться”:
- при свертке баз мы так сверяем остатки по регистрам “до/после” - бит-в-бит, включая бухгалтерию;
- при переносе пересчёта итогов на уровень СУБД - результат сверяется с эталонным платформенным пересчётом;
- при смене механизма прав - матрицей эквивалентности (та же идея: зафиксированный эталон против факта);
- при передаче пакета обмена по FTP - SHA-256 отправленного файла против принятого: в обмене через FTP с докачкой пакет не попадёт в загрузку, пока суммы не сошлись. Зачем это нужно, видно по обрыву пакета обмена на FTP: после разрыва на сервере остаётся огрызок под настоящим именем, и без суммы его не отличить от целого файла.
Итог
“Вроде сходится” - это не приёмка, это надежда. SHA-256 по нормализованной выгрузке стоит один вечер на постановку процесса и навсегда снимает два риска: молча сломать отчёт при оптимизации и бесконечно спорить о том, сломали ли. Дёшево, скучно, работает - как всё лучшее в эксплуатации.
Хотите, чтобы ваши отчёты ускорили с такими же гарантиями - посмотрите, как мы делаем оптимизацию: каждый деплой с доказательством идентичности, а не с “должно быть нормально”.