Как стать автором
Обновить
31.91
Тензор
Разработчик системы Saby
Сначала показывать

PostgreSQL Antipatterns: «вращаем» JSON

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров5.4K

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

Сегодня столкнулся с очередным нетипичным вариантом использования - "перекладыванием" значений из JSON-строк в столбцы.

Давайте сделаем это попроще.

Читать далее

Знакомство с Docker или зачем это всё нужно

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров23K

Всем привет. Меня зовут Алексей, вместе с командой я занимаюсь разработкой прикладных решений в системе Saby компании Тензор. В своей статье хочу поговорить про Docker.

При знакомстве с любой технологией важно понимать, зачем инвестировать своё время в её изучение. Для этого нужно иметь хотя бы общее представление о предметной теме. Сейчас, когда Docker используется повсеместно, многие разработчики (особенно молодые) относятся к нему, как к данности, при этом не до конца понимая, зачем, собственно, он используется и какие проблемы решает. На Хабре есть ознакомительные статьи про Docker, однако они не в полной мере (вернее, не в той мере, в которой хотелось бы мне :) ) освещают данный вопрос. Так возникла идея написания этой статьи. При ее подготовке были использованы: информация из книги Docker In Action, данные с профильных сайтов, собственные разработки для выступления на внутрикорпоративном митапе Тензора, материалы с IT-форумов и, конечно, личный опыт. Если вы опытный разработчик/администратор/devops, и уже давно используете Docker, вы вряд ли узнаете что-то новое из статьи и можете смело проходить мимо. Если же ваш профессиональный путь только начинается, надеюсь, что этот материал поможет вам в освоении данной технологии.

Читать далее

PostgreSQL Antipatterns: когда мешает внешний ключ

Время на прочтение5 мин
Количество просмотров19K

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

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

Читать далее

Разгоняем JS-парсер с помощью WebAssembly (часть 1: базовые возможности)

Время на прочтение7 мин
Количество просмотров5K

В прошлой статье, посвященной выяснению победителя в состязании JS-парсеров строки buffers-атрибута узла плана PostgreSQL, мы дошли до факта, что самый эффективный вариант - реализовать примитивный конечный автомат и никогда не трогать регулярные выражения и любые операции над строками сложнее .charCodeAt.

Такой код на тестовом нормализованном наборе показывает время порядка 48ms на 6.3MB или около 130MB/s, что примерно в 11 раз быстрее наивного варианта со .split.

Но всегда остается вопрос: "А еще быстрее - можно?"

Чтобы приблизиться к возможностям "железа", но по-прежнему остаться в инфраструктуре JavaScript, сегодня мы научимся решать эту задачу с использованием WebAssembly и SIMD-инструкций, постаравшись по пути споткнуться обо все подводные камни.

Читать далее

PostgreSQL Antipatterns: «Должен остаться только один!»

Время на прочтение3 мин
Количество просмотров16K
На SQL вы описываете «что» хотите получить, а не «как» это должно исполняться. Поэтому проблема разработки SQL-запросов в стиле «как слышится, так и пишется» занимает свое почетное место, наряду с особенностями вычисления условий в SQL.

Сегодня на предельно простых примерах посмотрим, к чему это может приводить в контексте использования GROUP/DISTINCT и LIMIT вместе с ними.

Вот если вы написали в запросе «сначала соедини эти таблички, а потом выкинь все дубли, должен остаться только один экземпляр по каждому ключу» — именно так и будет работать, даже если соединение вовсе не было нужно.

И иногда везет и это «просто работает», иногда — неприятно сказывается на производительности, а иногда дает абсолютно неожидаемые с точки зрения разработчика эффекты.


Ну, может, не настолько зрелищные, но…

«Сладкая парочка»: JOIN + DISTINCT


SELECT DISTINCT
  X.*
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
WHERE
  Y.bool_condition;

Как бы понятно, что хотели отобрать такие записи X, для которых в Y есть связанные с выполняющимся условием. Написали запрос через JOIN — получили какие-то значения pk по несколько раз (ровно сколько подходящих записей в Y оказалось). Как убрать? Конечно DISTINCT!
Читать дальше →

PostgreSQL Antipatterns: вычисление условий в SQL

Время на прочтение4 мин
Количество просмотров16K
SQL — это не C++, и не JavaScript. Поэтому вычисление логических выражений происходит иначе, и вот это — совсем не одно и то же:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()

В процессе оптимизации плана исполнения запроса PostgreSQL может произвольным образом «переставлять» эквивалентные условия, не вычислять какие-то из них для отдельных записей, относить к условию применяемого индекса… Короче, проще всего считать, что вы заранее не можете управлять тем, в каком порядке будут (и будут ли вообще) вычисляться равноправные условия.

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


Данные и работа с ними — основа нашего комплекса СБИС, поэтому нам очень важно, чтобы операции над ними выполнялись не только корректно, но и эффективно. Давайте посмотрим на конкретных примерах, где могут быть допущены ошибки вычисления выражений, а где стоит улучшить их эффективность.
Читать дальше →

PostgreSQL Antipatterns: меняем данные в обход триггера

Время на прочтение3 мин
Количество просмотров12K
Рано или поздно многие сталкиваются с необходимостью что-то массово исправить в записях таблицы. Я уже рассказывал, как это делать лучше, а как — лучше не делать. Сегодня расскажу о втором аспекте массового обновления — о сработке триггеров.

Например, на таблице, в которой вам надо что-то поправить, висит злобный триггер ON UPDATE, переносящий все изменения в какие-нибудь агрегаты. А вам надо все пообновлять (новое поле проинициализировать, например) так аккуратно, чтобы эти агрегаты не затронулись.

Давайте просто отключим триггеры!


BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- тут долго-долго
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

Собственно, тут и все — все уже висит.

Потому что ALTER TABLE накладывает AccessExclusive-блокировку, под которой никто параллельно выполняющийся, даже простой SELECT, ничего из таблицы прочитать не сможет. То есть пока эта транзакция не закончится, все желающие даже «просто почитать» будут ждать. А мы помним, что UPDATE у нас до-о-олгий…
Читать дальше →

SQL HowTo: рисуем морозные узоры на SQL

Время на прочтение2 мин
Количество просмотров7.1K


Немного SQL-магии под катом: математика, рекурсия, псевдографика.

Заодно вспоминаем под Новый год формулу угла между векторами:

Читать дальше →

SQL HowTo: Black and White (Puzzle Hunt 2010)

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров1.6K

Некоторые головоломки можно решать на SQL just for fun, а часть получается выразить на этом декларативном языке даже эффективнее других, императивных.

Попробовать сделать более наглядное решение, а заодно познакомить с некоторыми нетривиальными возможностями PostgreSQL меня натолкнул пост о решении на Python задачи Black and White.

Читать далее

Курс «PostgreSQL для начинающих»: #4 — Анализ запросов (ч.2 — узлы получения данных)

Уровень сложностиСредний
Время на прочтение12 мин
Количество просмотров17K

Продолжаю публикацию расширенных транскриптов лекционного курса "PostgreSQL для начинающих", подготовленного мной в рамках "Школы backend-разработчика" в "Тензоре".

В первой части лекции мы узнали, что такое план выполнения запроса, как и зачем его читать (и почему это совсем непросто), и о каких проблемах с производительностью базы он может сигнализировать. В этой - разберем, что такое Seq ScanBitmap Heap ScanIndex Scan и почему Index Only Scan бывает нехорош.

Как обычно, для предпочитающих смотреть и слушать, а не читать - доступна видеозапись (часть 1часть 2) и слайды.

Читать далее

Любимая задачка на знание React

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров27K

Всем привет! Меня зовут Олег и я fullstack-программист в компании Тензор. Опыт в разработке, без малого, 20 лет (как-то раз батя спаял на кухне ZX Spectrum и все заверте..., сам не понял как так вышло). В данный момент являюсь тимлидом собственной команды разработчиков, которая периодически нуждается в пополнении толковыми программистами.

Как и многие руководители, я активно принимаю участие в подборе сотрудников для себя и помогаю на собесах коллегам соседних отделов.

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

Если вы тоже в вечном поиске классных фронтендеров или сами часто проходите собесы - велком в эту статью :)

Итак, задачка...

PostgreSQL в «Тензоре» — публикации за год

Время на прочтение16 мин
Количество просмотров6.5K
Ровно год назад с рассказа о нашем сервисе визуализации планов запросов мы начали публикацию на Хабре серии статей, посвященных работе с PostgreSQL и его особенностям. Это уже пройденные нами «грабли», интересные наработки, накопившиеся рекомендации, применяемые в разработке «Тензора» — те вещи, которые помогают нам делать СБИС более эффективным.


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


И все их данные надо где-то хранить и эффективно извлекать. Поэтому еще в далеком 2012 году мы сделали ставку на PostgreSQL, и теперь это основное хранилище данных наших сервисов:

  • почти 9000 баз общим объемом 1PB
  • свыше 200TB данных клиентов
  • 1500 разработчиков работают с БД

Чтобы упорядочить накопившиеся знания, за минувший год мы опубликовали более 60 статей, в которых делимся своим реальным опытом, проверенным практикой «сурового энтерпрайза». Возможно, какие-то из них вы пропустили, поэтому под катом мы собрали дайджест, где каждый разработчик и DBA найдет что-то интересное для себя.

Для удобства все статьи разбиты на несколько циклов:

  • Анализ запросов
    Наглядно демонстрируем все тайны EXPLAIN [ANALYZE].
  • SQL Antipatterns и оптимизация SQL
    Понимаем как [не] надо решать те или иные задачи в PostgreSQL и почему.
  • SQL HowTo
    Пробуем подходы к реализации сложных алгоритмов на SQL для развлечения и с пользой.
  • DBA
    Присматриваем за базой, чтобы ей легко дышалось.
  • Прикладные решения
    Решаем с помощью PostgreSQL конкретные бизнес-задачи.
Читать дальше →

Мониторим базу PostgreSQL — кто виноват, и что делать

Время на прочтение7 мин
Количество просмотров37K
Я уже рассказывал, как мы «ловим» проблемы PostgreSQL с помощью массового мониторинга логов на сотнях серверов одновременно. Но ведь кроме логов, эта СУБД предоставляет нам еще и множество инструментов для анализа ее состояния — грех ими не воспользоваться.

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


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

Сегодняшняя статья — о том, какие выводы можно сделать, наблюдая в динамике различные метрики баз PostgreSQL-сервера, и где может скрываться проблема.
Читать дальше →

Рецепты для хворающих SQL-запросов

Время на прочтение7 мин
Количество просмотров66K
Несколько месяцев назад мы анонсировали explain.tensor.ru — публичный сервис для разбора и визуализации планов запросов к PostgreSQL.

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



Прислушивайтесь к ним, и ваши запросы «станут гладкими и шелковистыми». :)

А если серьезно, то многие ситуации, которые делают запрос медленным и «прожорливым» по ресурсам, типичны и могут быть распознаны по структуре и данным плана.

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



Давайте чуть подробнее рассмотрим эти кейсы — как они определяются и к каким рекомендациям приводят.

Ближайшие события

Юнит-тесты. Быстрый старт – эффективный результат (с примерами на C++)

Время на прочтение14 мин
Количество просмотров67K


Вместо вступления


Всем привет! Сегодня хотелось бы поговорить о том, как просто и с удовольствием писать тестируемый код. Дело в том, что в нашей компании мы постоянно контролируем и очень ценим качество наших продуктов. Еще бы – ведь с ними ежедневно работают миллионы человек, и для нас просто недопустимо подвести наших пользователей. Только представьте, наступил срок сдачи отчетности, и вы тщательно и с удовольствием, используя заботливо разработанный нами пользовательский интерфейс СБИС, подготовили документы, еще раз перепроверили каждую циферку и вновь убедились, что встречи с вежливыми людьми из налоговой в ближайшее время не будет. И вот, легким нажатием мыши кликаете на заветную кнопку «Отправить» и тут БАХ! приложение вылетает, документы уничтожаются, жарким пламенем пылает монитор, и кажется, люди в погонах уже настойчиво стучат в двери, требуя сдачи отчетности. Вот как-то так все может и получиться:
Читать дальше →

PostgreSQL Antipatterns: создаем JSON из строки

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров5.2K

Я уже не раз поднимал в статьях тему [не]эффективной работы с json[b] в PostgreSQL — и как его лучше превращать в выборку, и как можно «транспонировать». Сегодня же рассмотрим некоторые возможности по его генерации на стороне базы.

Читать далее

Псс, парень… индекс нужен?

Время на прочтение8 мин
Количество просмотров24K

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

Мы научили наш сервис визуализации планов PostgreSQL отвечать на эти вопросы, и под катом расскажем, чем именно он руководствуется в своих рекомендациях.

Читать далее

SQL HowTo: разные варианты работы с EAV

Время на прочтение3 мин
Количество просмотров25K

Соблазн использовать модель EAV (Entity-Attribute-Value) при организации структуры БД весьма велик, особенно когда предметная область заранее плохо известна (или разработчик просто не хочет в нее углубляться). Это ведь так удобно - создать "универсальный" способ описания характеристик объектов, который больше не потребует доработок базы ни при появлении новых типов объектов, ни при возникновении новых атрибутов...

Однако, за любую универсальность приходится платить сложностью и производительностью запросов - так что json[b] может оказаться более эффективной заменой. Но если уж такая модификация невозможна - давайте попробуем выжать максимум производительности из доставшегося нам legacy на самом простом примере.

Читать далее

PostgreSQL Antipatterns: навигация по реестру

Время на прочтение4 мин
Количество просмотров11K
Сегодня не будет никаких сложных кейсов и мудреных алгоритмов на SQL. Все будет очень просто, на уровне Капитана Очевидность — делаем просмотр реестра событий с сортировкой по времени.

То есть вот лежит в базе табличка events, а у нее поле ts — ровно то самое время, по которому мы хотим эти записи упорядоченно показывать:

CREATE TABLE events(
  id
    serial
      PRIMARY KEY
, ts
    timestamp
, data
    json
);

CREATE INDEX ON events(ts DESC);

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

#0. «Я у мамы погроммист»


cur.execute("SELECT * FROM events;")
rows = cur.fetchall();
rows.sort(key=lambda row: row.ts, reverse=True);
limit = 26
print(rows[offset:offset+limit]);

Даже почти не шутка — редко, но встречается в дикой природе. Иногда после работы с ORM бывает тяжело перестроиться на «прямую» работу с SQL.

Но давайте перейдем к более распространенным и менее очевидным проблемам.
Читать дальше →

SQL HowTo: один индекс на два диапазона

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров4.7K

В прошлой статье я показал, как условие с парой однотипных неравенств, плохо поддающееся индексации с помощью btree, можно переделать на эффективно gist-индексируемое в PostgreSQL условие относительно диапазонных типов, а наш сервис анализа планов запросов explain.tensor.ru подскажет, как именно это сделать.

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

dt >= '2023-12-01'::date AND dt <= '2023-12-31'::date AND

sum >= 10000::numeric AND sum <= 20000::numeric

Читать далее

Информация

Сайт
saby.ru
Дата регистрации
Дата основания
Численность
5 001–10 000 человек
Местоположение
Россия