Как стать автором
Обновить
18
0.2
Иван Старостин @IVNSTN

EAccessViolation

Отправить сообщение

В тексте есть ответ, и это поведение задокументировано. У ошибок предусмотрен разный уровень серьезности, обычные ошибки к прерыванию пакета команд и откату транзакции не приводят. Если только сам программист не сделал обработку ошибок так, чтобы прерывалось и откатывалось. Такое поведение а) скорее оставлено для обратной совместимости б) позволяет пользоваться сейв-пойнтами и иногда действительно игнорировать ошибки в стиле "а, ну и ладно, потом проапдейчу" в каких-то отдельностоящих сценариях; тот же дэдлок с повтором в цикле.

Для более однозначного поведения придумана опция XACT_ABORT (там в конце страницы как раз пример с ошибками по FK), но она выставлена в OFF по умолчанию - снова из соображений обратной совместимости. И выражение THROW, призванное заменить RAISERROR, по поведению как раз больше похоже на генерацию исключений в других языках: вылетаем либо в CATCH, либо весь батч прерывается, если находимся вне TRY-CATCH. RAISERROR (на котором написано всё легаси) ничего не прерывает, потому приходилось после него писать RETURN. THROW же превращает этот RETURN в unreachable code. Нюансов - толпа. Об том и вопрос.

TRUNCATE в контексте isolation

В контексте durability и в еще более конкретном контексте про "городские легенды" - в тексте заход вроде бы достаточно прозрачный.

И всяких других граблях ... TRUNCATE

значения локальных переменных, даже табличных, в него явно не входят

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

Ошибки можно и через механизм raiserror передавать

Это уже почти сформулированная распространённая задачка с собеседований: сколькими способами можно вернуть целочисленное значение из хранимки.

Рандомный код возврата хоть при успехе, хоть при неуспехе - такая же не соблюдённая базовая гигиена, как NOCOUNT и прочие мелочи. На скорость выполнения запросов не влияет, но про отношение к аккуратности, готовность соблюдать соглашения и причесывать старьё немного намекает.

несложный запрос с рекурсией и оконными функциями

такая ветка в описанной схеме собеседования присутствует.

Спасибо! Интересная дискуссия.

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

генерирует описание интерфейсов по заголовкам и комментариям и выкладывает артефакты в Nexus

так-то "для галочки" сделали получается. "Вот <несколько тысяч сигнатур>. Такое описание системы". Хотя, смотря что называть документацией. Хоть что-то - тоже польза.

Дайте технических подробностей.

SSDT/DacFx/SqlPackage не пользуетесь совсем?

Весь блок про тесты интересен, но

Вся логика Arrange/Act/Assert пишется на SQL.

достаточно добавить одну строку в DCL обобщенного теста

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

как в той песне "мне всё понятно, но что конкретно ты имела ввиду?". Реализацию, видимо, не покажете, но покажите хотя бы описанную обвязку для одного теста. "Вот хп, вот для нее кусок на SQL, вот кусок JSON, вот так это склеивается, вот так мы это всё стартуем". Конкретный пример.

И если вы пишете на хранимках (и триггерах) разве большая часть тестируемого кода не попадает под определение "сложных случаев"? Не получилось ли так, что упростить удалось только и без того простые тесты, а со сложными как будто перемудрили?

автогенерацию кода взаимодействия с другими сервисами

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

И снова про тесты: если

огромного легаси монолита

то как

Скрипты накатываются на указанный в конфигурации сервер БД, это может быть машина разработчика

? В смысле даже физически.

И скриншот результатов от SqlCover несколько подозрительный. Запуск тестов встроен в пайплайн, в сборку интеграционных веток или их дергает в нужный момент ответственный работник? А в сборку PR? SqlCover через Extended Events плодит файлики весом в десятки гигабайт - это всё тянет стандартная машина любого вашего разработчика?

качество кода низкое, особенно в последнее время

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

и даже в правительстве

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

В некоем воображаемом, аморфном "agile" перегружают задачами? Пишут как попало? Код проектов и отзывы участников последних крупных проектов, написанных под каскадом с релизами раз в три года в студию!

Джуну не дают "больше времени" на то, чтобы "вылизать" те полторы говнофункции, которые ему доверили наковырять? Молитесь на того лида, который в состоянии сообразить и настоять на прекращении бессмысленных ковыряний в чем-то никому не нужном. Так-то конечно джуну с мидлом виднее, на что нужно потратить ближайшие полгода, но прочие глупцы-то не в курсе истинной природы вещей.

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

Попытки систематизировать знания и найти универсальный подход к борьбе с неопределенностью всегда заслуживают внимания и уважения по крайней мере к самому устремлению.

Было бы здорово:

  • разобраться со значением слова "проект" и в каком ключе вы его употребляете в своей статье; очевидно, здесь применяется максимально широкое трактование, что в общем случае плохо и гарантирует непонимание со стороны слушателя и закипание головного мозга

  • "Управление проектами" != "Управление процессами" != "Управление командами" != "У нас есть колонки, по которым можно двигать таски" как уже выше заметили; было бы очень здорово всё называть своими именами

  • разобраться с терминами "SDLC", "методология", "идеология", "фреймворк", вернуться к табличке, в которой нам нужно выбрать между методологиями управления проектами ("методологиями разработки"?) Agile, Scrum, Lean и Waterwall и постараться не провалиться сквозь землю; набор заблуждений и неточностей распространенный, сильно переживать не стоит

как это можно дотащить до воды

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

А чего наминусили? "Троллейбус из буханки" и есть, он же "деревянные (буквально) наушники". Сильно плохого в этом ничего нет, главное отдавать себе отчет, что виндсерфер устроен не совсем так и что проект именно про сделать самому что-то похожее, а не про виндсерфинг. Заходя по ссылке думал увидеть рассуждения про композитные материалы и/или проектирование того, что действительно в современном мире является оборудованием для виндсерфинга, а это оказался скан журнала "Сделай сам '93" (к слову, как сейчас помню как нашел стопку их где-то в папкином шкафу и там был выпуск с чертежами катамарана для постройки из фанеры и прочих "возьмите два поплавка от гидросамолета..." - романтика!)

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

Личный опыт и самодельничанье - дело хорошее, но в статье много лишнего. Весь блок про кайт - это, извините, отчасти в духе "а вот у рыб шерсти нет - и опять про блох рассказываешь". Статья же не об этом. Ну и про миграцию звёзд, и то что "мотоциклы - прошлый век, плацкартные вагоны - наше всё!" и т.п. Вы же не в теме? Не в теме. Парапланы на замену дельтапланов не приходили, это просто разное так же как и кайт с виндсерфом. Если вычесть не самые удачные рассуждения за современность и тенденции, получится шикарная ламповая история про поделки/проделки из далекой юности. Ламповости бы добавили черно-белые фото с водоема, сделанные непременно на фотоаппарат "Зенит".

Робби Нейш требует от виндсерфа от него отстать, поскольку давно перешел на кайт

И, к слову, он давно уже не столько "звезда", сколько "легенда". Возраст как бы намекает.

SqlPackage создает набор скриптов, которые позволяют с любой версии обновиться до актуальной?

Именно так: привести любого состояния БД к тому что надо, что в репозитории/в релизе.

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

Выявит, но только отправит на рефреш. Если хп менялись, то альтернет. "На всякий случай" ничто никогда не дропается.

CREATE VIEW view_name AS SELECT table_name.*

Подстраиваться под эти ужасы на мой взгляд гиблое направление, которое приводит к появлению "Больше костыль при отсутствии решения, чем решение" (мой коммент выше). Исходники надо линтить, подобные ужасы выявлять и устранять абсолютно все. SELECT * имеют право существовать только в условно одноразовых говноскриптах. Если нет SELECT *, то не существует хп или вьюх, которые каким-то непостижимым образом берут и неявно меняют свое поведение, потому что где-то в таблицу колонку добавили или две. Такого не существует как явления (если навести порядок). Гугл говорит, что для postgresql какие-то линтеры есть. К SonarQube есть плагин с поддержкой postgresql.

Порядок приёма PR может повлиять на конечный вид view_name ?

Это уже про что-то за гранью добра и зла.

И как вы по тэгу в гите, который отдает вам всё содержимое репозитория, понимаете, какие из триллиона миграций не нужно, а какие нужно применять в данном конкретном релизе? Верно ли я понимаю, что автоматизации вокруг описанной системы примерно ноль и вы всё "понимаете" и собираете руками? И правильную последовательность дропов, и правильный набор миграций.

И правильно ли я понял, что остальные вопросы из первого комментария останутся без ответа?

Это уменьшит риск случайной замены объектов с потерей

Что такое "случайная замена функции" и с потерей чего? Особенно в контексте описанного сценария, где дропается вообще всё и потом создается вообще всё.

> Как тогда рулите тем, что является дельтой, которую нужно применить к серверу? На сервере накатывается код соответствующий релизу

как вы определяете, какой код соответствует какому релизу?

Что-то я как будто середину чьего-то разговора застал... Не очень понятно, на какую дискуссию рассчитан пост без деталей реализации и примеров из жизни. Соберите минимальную репу на GitHub или скрины того, что у вас есть приложите. Как выглядит репозиторий, код пишется в Notepad++ и вы узнаете о том, что синтаксис кривой только на деплое или как это все у вас происходит.

Из описания не понял, так у вас миграции (дельты) хранятся в Git или финальные определения объектов. По таблицам больше похоже, что миграции (ALTER TABLE ADD COLUMN), по хп больше похоже что скрипт один и навсегда, т.е. смесь подходов. Как тогда рулите тем, что является дельтой, которую нужно применить к серверу? Ф-и и хп, поскольку описано безусловное пересоздание, вероятно, всегда "тупо" все накатываете. Больше костыль при отсутствии решения, чем решение.

Упоминается некий скрипт, в котором ф-и и хп в правильном порядке дропаются и создаются - вы его "на руках" держите или есть автоматизация, которая эту последовательность строит глядя в код?

У этого подхода есть и отрицательная сторона — на уровне скрипта сложнее оценить влияние изменения структуры хранения данных на представления и функции. В момент внесения изменения их уже нет, не проследить цепочку зависимостей, а потом они будут пересозданы уже с учетом изменившейся структуры хранения. Здесь целесообразно применять дополнительные инструменты, сравнивающие структуру БД до внесения изменения и после, чтобы выявить все изменения.

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

все сущности пересоздаются каждый раз

не самое удачное жонглирование словом "сущности" в разговоре про Relational DB. Функции и процедуры никто сущностями не называет.

Пересоздание таких сущностей занимает немного времени

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

крупных проектов с небольшим уклоном в сторону PostgreSQL

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

И решение вы оцениваете как полностью ваш локальный велосипед (без оценки качества, только уникальность) или его можно сравнить со способом работы DbUp, SqlPackage или чего-то еще?

А неправильно - не делать. Понятно.

Так не будет же, о чем и речь. Если структура будет создана несовместимая, то ошибка будет абсолютно непонятная и в месте никак не связанном с точкой "проверки" через DROP IF EXISTS. А если структура окажется совместимой, то код ниже по уровням вложенности молча и с удовольствием пойдет лопатить вообще не те данные. Этот DROP - почти то же самое, что WHILE @@TRANCOUNT > 0 COMMIT потому что мне тут чужая транзакция не нужна. Мне тут ваши внешние таблицы не нужны - это точно не проверка и точно распоряжение объектом, про который текущий контекст ничего не знает.

чтобы при проверке увидеть есть ли пересечение в именах локальных временных таблицах

А как кто-то или что-то это увидит? И "проверки" ведь нет, есть вышибание табуретки из под ног вложенных и внешнего батчей. Таблица спокойно подменится, понятной ошибки не будет ни в какой момент.

Условный THROW IF EXISTS - это да, это была бы проверка, которая вовремя бы дала понять разработчику, что есть пересечение по именованию.

В целом со всем согласен, но есть пара моментов

DROP TABLE IF EXISTS перед её созданием

В ad-hoc скриптах может быть удобно, но в разработке это все-таки скорее антипаттерн. В хранимке такой код свою таблицу дропнуть никогда не сможет - она еще не создана. А распоряжаться внешним объектом неизвестного для текущей области видимости назначения он не имеет права - хп ничего про тот объект не знает, это не ее зона ответственности. Полезного этот фрагмент точно ничего не сделает, а навредить и сильно запутать поиск причины проблемы может.

пример
CREATE PROC dbo.level_three
AS
BEGIN
    SELECT 'level_three' AS [level_three], OBJECT_ID('tempdb..#aaa', 'U') obj_id, * FROM #aaa
END;
GO

CREATE PROC dbo.level_two
AS
BEGIN
    SELECT 'level_two' AS [level_two], OBJECT_ID('tempdb..#aaa', 'U') obj_id

    DROP TABLE IF EXISTS #aaa;

    CREATE TABLE #aaa (a VARCHAR(10), b FLOAT);
    INSERT #aaa (a, b) VALUES ('22', 3.14);

    SELECT 'level_two' AS [level_two], OBJECT_ID('tempdb..#aaa', 'U') obj_id

    EXEC dbo.level_three;
END;
GO

CREATE PROC dbo.level_one
AS
BEGIN
    CREATE TABLE #aaa (a INT, b VARCHAR(10));

    INSERT #aaa (a, b) VALUES (1, 'b');

    SELECT 'level_one' AS [level_one], OBJECT_ID('tempdb..#aaa', 'U') obj_id

    EXEC dbo.level_two;

    SELECT 'level_one' AS [level_one], * FROM #aaa;
END;
GO

EXEC dbo.level_one;
GO

DROP PROC IF EXISTS dbo.level_one;
GO

DROP PROC IF EXISTS dbo.level_two;
GO

DROP PROC IF EXISTS dbo.level_three;
GO

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

А ещё лучше <запрос> выполнить до COALESCE

Предложил бы сразу рекомендацию и переписать, не предлагать то, что приносит в код новые потенциальные проблемы. Так-то и NULL может быть нужен, и не трогать переменную, если ничего не нашлось - по ситуации; рекомендация довольно абстрактная. И в SELECT-SET, и в SET-SELECT много чего нужно иметь ввиду и понимать, что ты делаешь.

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

свыше половины россиян (58,8%) ведут учет всех расходов и доходов на регулярной основе и распределяют свой бюджет

https://wciom.ru/analytical-reviews/analiticheskii-obzor/impulsivnye-pokupki

«подушка безопасности» есть у 54% респондентов

https://wciom.ru/analytical-reviews/analiticheskii-obzor/sberezhenija-rossijan-monitoring

Информация

В рейтинге
2 287-й
Откуда
Таганрог, Ростовская обл., Россия
Зарегистрирован
Активность