Pull to refresh
1
0
Николай Налбантов @NickNal

Data Engineer

Send message

Я абсолютно не против того, чтобы не пихать бизнес-логику в хранимки

Но те, кто об этом пишет статьи, обычно предлагают такие альтернативы:

  • аналогичный код на Питоне / JS / PHP..., ещё и обезображенный использованием ORM

  • dbt и его аналоги, которые в точности повторяют функционал хранимок, но через богомерзкую Jinja

Ещё ни разу не видел кейса, чтобы написали: "мы выпилили хранимки, вместо них написали высокопроизводительный код на С / Java / Rust..., который работает с данными по бинарному протоколу"

А замена хранимок на dbt / функции во внешних скриптах - это тот же половой орган, только в другой руке

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

Ух ты, кто-то ещё использует MySQL в 2024 году

Ладно б ещё хотя б с MariaDB сравнивали, она и то живее и активнее поддерживает фичи из новых редакций стандарта SQL (system-versioned, bitemporal tables и т. д.)

Сейчас MySQL по функционалу уже скорее с SQLite соперничает, чем с PG

Я плохо знаком с мёртвыми языками типа Пыхи и ещё хуже с его ОРМ, открыл почитать документацию по Yii2

Ну и сразу нарвался на типичную ОРМ-логику - joinWith по умолчанию генерирует два запроса на получение датасетов: левый джойн первой таблицы со второй и выборку из второй таблицы с коррелированным подзапросом (where in (...))

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

Можно я не буду эту лажу воспроизводить?)

Именно SQL ограничен декларативной парадигмой, а сверхсложную логику пишут на языках общего назначения

Срочно устраивайтесь в Databricks, а то они зачем-то Spark Dataframe API трансформируют на Spark SQL, а не наоборот, дилетанты!1! И всякие Iceberg, Hudi и другие профессиональные инструменты для работы с данными почему-то продолжают развиваться в парадигме SQL в первую очередь.

Ну и с прикладной стороны, по секрету скажу, куча "сверхсложной логики" по работе с данными в крупнейших банках и телеком-провайдерах написана в БД - это проще, производительнее, надёжнее

Если в вашем пузыре клепания CRUD-сайтиков никто не умеет в SQL на профессиональном уровне, это не значит, что он чем-то ограничен) Вполне себе Тьюринг-полный язык программирования

ORM в следствии своей парадигмы, толкает на написание работы с данными внутри кода, что приводит цельности логики и его дальнейшему рефакторингу.

Осталось только понять зачем))
Данные хранятся вне приложения, строго типизированы вне приложения, ACID реализуется вне приложения, данные из БД легко выгружаются в нативные объекты языка (словари, кортежи, массивы, датафреймы...)

Логика кода от его обфускации в ORM или без него не должна меняться или становиться более или менее цельной

То же самое с рефакторингом, только SQL переписывать, тестировать и профилировать куда проще

Вопрос - зачем вообще делать маппинг отношений в объекты в приложении?)

Мне кажется, что мне вас есть чем приятно удивить.

Страшно представить, как какая-нибудь SQLAlchemy справится с разветвлённой иерархией ролей в PostgreSQL, когда она на джойнах нескольких таблиц и базовых DML-операциях начинает спотыкаться)

Даже не хочу знать)

Чтобы всем было наглядно видно, что эту мешанину будет сложно поддерживать

Я принципиально не понимаю как кривую и функционально неполную абстракцию над кодом может быть проще поддерживать, чем чистый, максимально explicit код, тем более такой простой, как SQL)

Не вижу от этого особой пользы для стандартных задач

Ну это ожидаемо)
К счастью, современные ОРМ уже залатали 99% дыр в безопасности, которыми они посвистывали ещё лет 5-7 назад. А сливы данных из-за такого отношения к инфобезу уже к ORM не относятся
Вот если б ORM делали бы вид, что ещё и ролевые модели в БД умеют генерировать, вот тогда б точно приехали))

P.S. завтра утром до ноута доберусь, может накидаю какие-то варианты, раз так сильно просите)

Господи, ну вы что, не представляете генерацию параметризованной SQL-лапши без ORM? Это ж просто строка, её можно вертеть как угодно через условия в переменных и if / циклы и т. д. Если не требуется джойнить managers - да просто не генерируй соответствующий кусок строки, и всё))

Нужно переиспользовать шаблон логики? Не беда, человечество давно придумало шаблонизаторы (Jinja, Twig и т.п.) и пользовательские функции на языках, встроенных в БД (что даёт не только более чистый и стабильный код и на стороне приложения, и на стороне базы, но ещё и более безопасный код - см. например security definer-функции в PostgreSQL).

Единственное, что действительно необходимо для работы с БД из приложения - драйвер для подключения к этой БД (примеры для Python - psycopg / asyncpg, cx-oracle, pyodbc и т.п.)

С телефона я сейчас печатать код не буду, 1 мая, увы, не за рабочим местом)

Но тут такой примитив, что даже ORM не должен налажать, наплодив n + 1 проблему, избыточные джойны и отбитые списки в where. Хотя я не уверен) Да и не факт, что вы сами знаете как этот запрос сейчас у вас фактически выполняется)

Тут не один запрос, а простейшая параметрическая кодогенерация. Это всегда решается на уровне приложения или процедурного языка (PL/SQL, T-SQL, PL/pgSQL). ORM для этого не обязателен, на любом языке программирования из коробки можно собрать такой же запрос, в т.ч. с защитой от SQL Injection

А где тег "вредные советы", "сарказм"?

Использование ORM и по смыслу (напиши мне SQL-запрос на основе команды на другом языке), и по качеству результата (ниже плинтуса) эквивалентно использованию ChatGPT для генерации SQL-запросов

Это стандартные объёмы транзакций небольшой-средней локальной платёжной системы. Или базы данных платформы с чатами / соцсети тоже не самого большого масштаба. Или телеметрии с датчиков крупного автопарка / завода

Ничего сверхъестественного в 2024 году в этом нет

Запретить погромистам менять структуру кода в новых версиях

Сломал обратную совместимость - к тебе выезжает Github-патруль и ломает палец

Так вижу

база по умолчанию собирает данные о распределении относительно всего лишь 100 значений (параметр default_statistics_target).

Это некорректная формулировка
Статистика собирается по 300 * default_statistics_target кортежам с такого же количества страниц. Т. е. , по дефолту, 300 * 100 = 30000 строк
И ещё default_statistics_target определяет количество корзин в гистограмме значений, тут без всякого множителя

См. комментарий в исходниках по поводу числа 300

Куча кода регулярно ломается при обновлении мажорных (а иногда и минорных) версий популярных библиотек, для этого и придумали всякие requirements.txt, virtualenv, контейнеры и т.п.

А тут переписывают значимую часть ядра языка на горизонте нескольких мажорных версий (5+ лет)

Не вижу проблемы и повода для ворчания

Нет солнца, дорого и массовое употребление алкоголя/веществ - всё как в Питере)

Так там тоже всё на триггерах)

В psql-hackers когда-то было большое обсуждение патча с добавлением temporal tables согласно ANSI-стандарта. В итоге решили забить, т.к. решили, что это добавит много проблем при редактировании таблиц (удаление/добавление/смена типа поля) при относительно небольшой пользе. К тому же триггеры с таким функционалом каждый может написать под себя, не ограничиваясь стандартным функционалом и синтаксисом.

Вот как раз два примера кастомных реализаций на триггерах)

Ну правда жизни такова, что в больших DWH пользователей принято бить ногами за плохие запросы))
Вспоминая навскидку несколько примеров с конференций, в Авито, кажется, запросы рядовых пользователей вроде перехватывает парсер, проверяет план и не пропускает вопиющие косяки. В Тинькофф похожий сервис имеет говорящее имя "Инквизитор".
И это не только Greenplum касается, а вообще всех крупных хранилищ. Слышал про кейсы, когда за плохие запросы в Snowflake в AWS аналитиков наказывали долларом (т.к. там непосредственную цену каждого запроса легко посчитать).

Возвращаясь к таблицам:
При рандомной дистрибуции мы просто всегда будем получать Redistribute / Broadcast Motion и никогда не получим пользы от Greenplum как от MPP. Это всё равно, что гонять запросы между репликами обычного (причём устаревшего PostgreSQL).
В идеальном мире надо стремиться выжимать из запросов максимум ситуаций, когда данные будут крутиться внутри одного слайса на отдельных сегментах, и только в конце собираться на мастере. Для этого нужны осмысленные с точки зрения бизнеса ключи дистрибуции.

Если распределить все ровненько по serial а Table4 random

Огромную партиционированную таблицу оставлять с random-дистрибуцией - плохая идея в любом случае. Стоит сделать суррогатный ключ и распределить таблицу по нему

Вот как будет работать броадкаст

При собранной статистике по всем таблицам броадкасты тут вряд ли случатся, будут Redistribute Motion
Правда может произойти Broadcast Motion данных из Table 4, если по условию where Date = Дата выберется небольшой объём данных (относительно объёмов Table 1 - Table 3) из одной партиции Table 4
Если вместо inner join в запросе будут left join, то и такой кейс для broadcast исключён

--
Худшее, что тут может произойти - перекосы (skew) в промежуточных джойнах, которые можно наглядно отловить с помощью explain analyze. Самый простой способ от них избавиться - разобрать многоэтажные джойны на последовательные операции и оптимизировать их по отдельности (фильтровать null, выбирать distinct значения ключей для джойна и т.д.). Greenplum может переварить портянки на 10+ джойнов, но это редко является оптимальной формой запроса.

Да, конечно

Пример:
create table if not exists t (id int) partition by hash (id);

create table if not exists hash_p_1
partition of t for values with(modulus 2, remainder 1);

create table if not exists hash_p_0
partition of t for values with(modulus 2, remainder 0);
  
insert into t
	select *
	from generate_series(1,100);
	
select * 
from hash_p_1;

Из-за этого уже превентивно перешёл на Debian 12.1

Интересно, когда уже поднимут 1С на Greenplum

Information

Rating
Does not participate
Location
Краснодар, Краснодарский край, Россия
Works in
Date of birth
Registered
Activity

Specialization

Database Developer, Database Architect
Senior
From 350,000 ₽
SQL
PostgreSQL
Python
Database
Oracle
Linux
Git
Neo4J
ELK Stack
Pgsql