Нет тут никаких болячек. Любой версионник тоже блокирует измененные строки, но при этом он не мешает читающим транзакциям видеть предыдущие версии строк (снэпшоты). А вот другие модифицирующие транзакции, если попытаются изменить те же самые строки, вынуждены будут подождать, пока первая транзакция не завершится и не "отпустит" их, и лишь затем смогут продолжать работу.
Статья напоминает о том, что порядок обработки строк в общем случае непредсказуем, и часто зависит от физического расположения строк в блоках на диске. И если 2 параллельные сессиии возьмутся обновлять одни и те же наборы строк, то мы можем получить взаимоблокировку.
Это классическая проблема, и автор в данной статье приводит её хрестоматийное решение. Многие новички сталкиваются с этим, и ломают голову потому что не понимают как работает СУБД.
Мне кажется, банковская карта нужна чтобы подтвердить вашу личность. Мало ли что вы там установите на этих серверах? Ограничений ведь никаких. Поэтому, видимо, не всякая карта им подходит.
Оракл рулит, я уже давно таким аккаунтом пользуюсь, всё очень круто.
К слову сказать, эти операторы pivot и unpivotпоявились впервые в Oracle DB 11g (2007). Позже они были реализованы и в MS SQL Server.
В бесплатном PostgreSQL с незапамятных времён есть функция crosstab(), реализующая то же самое (находится в модуле tablefunc).
В MySQL конечно же это не завезли, но ничего страшного, ведь используя обычный SQL без всяких волшебных операторов можно легко получить тот же результат при помощи агрегации с case, в любой СУБД.
Неплохо было бы упомянуть, что Hash Join и Merge Join используются только для соединений с условием равенства (a.col1 = b.col2). Иначе только Nested Loops, он универсальный и годится для любых условий.
Реально достал уже этот детсад. Поставил минус посту. Открываешь почитать тематическую ленту после тяжёлого трудового дня, и видишь этот бред с картинками. Люди с цветными линзами от телескопа вместо глаз.
Во первых, я бы рекомендовал захинтовать вставку при помощи APPEND NOLOGGING, чтоб ускорить и не генерить redo для этих данных. А ещё покурите асинхронный коммит, например https://www.orafaq.com/node/93. Я вижу у вас партиции, следовательно это решение предназначено для прода а не для разработки.
А не лучше ли в таком случае вместо хранения логов в базе слать их во внешнюю систему? Можно написать простейший Java source пакетик (или или готовый байткод загрузить в базу), и через него стримить наши логи в Apache Kafka или в любую другую шину? Оттуда направлять это куда душе угодно, в любую time-series database, или в старый добрый Prometheus, потом их можно будет видеть в системе мониторинга вкупе с остальными метриками и делать выводы, например в Grafana Loki. Заодно и retention policy для логов проще управлять. И можно алерты настроить чтоб по мейлу или прям в телегу получать важные оповещения.
Странно, в списке shapes нету 1 GB RAM always free машины, самая мелкая "VM.Standard.E2.1" 8 GB RAM. Ищу во вкладке "Specialty and Legacy", где она должна быть по идее. Может это от региона зависит? Хотя в справке написано что для моего региона always free VM доступны.
Да, похоже вы правы, действительно, работает! Возможно, это послабление было сделано специально, по каким-то неизвестным нам причинам, и открывать тикет навряд ли стоит, потому что обратная совместимость важнее и всё такое. Я точно знаю по опыту работы с другими СУБД что этот constraint необходим, и иногда даже задаю этот вопрос на собеседованиях.
В теории реляционных баз данных для внешнего ключа обязателен потенциальный ключ в родительском отношении. Одно из свойств потенциального ключа — это его уникальность.
Согласитесь, что ключи и индексы — это совершенно разные вещи. Ключи обеспечивают целостность и непротиворечивость данных с точки зрения бизнес правил, в то время как индексы — это чисто техническая вещь для ускорения доступа к данным. Как говорится, мухи отдельно, котлеты отдельно. Ключ должен ссылаться на ключ, мы связываем ограничения целостности друг с другом.
В общем случае индекс не обязан присутствовать для поддержки уникального ограничения, но крайне желателен для больших таблиц во избежание full/seq-scan. Для маленьких табличек он точно не нужен, и в других СУБД индекс не создаётся автоматически при создании уникального ключа.
Так что с документацией всё нормально, она просто следует общеизвестным базовым правилам. А вот реализация немножко кривая.
Спасибо за отличную статью! Хотел прояснить одну вещь.
В этот момент может возникнуть вопрос – зачем вообще создавать ограничение, если индекс выполняет ровно то, что требуется – гарантирует уникальность значений?
Единственное отличие, которое удалось найти, состоит в том, что ограничения могут быть отложенными (deferrable), а индексы – нет.
Ответ очень простой: на ограничения уникальности можно ссылаться из внешних ключей. Просто индекса в этом случае недостаточно. Читаем документацию:
A foreign key must reference columns that either are a primary key or form a unique constraint. This means that the referenced columns always have an index (the one underlying the primary key or unique constraint).
Попутно у некоторых людей возникает вопрос: а в чём тогда отличие первичных ключей от уникальных? Ответ: первичный ключ не допускает значений NULL, и он лишь один на таблицу.
Довольно сложно найти документацию, описывающую алгоритмы работа кеша PostgreSQL. Для желающих изучить этот вопрос более углубленно, привожу ссылку: Inside the PostgreSQL Shared Buffer Cache.
сначала там отказались от использования совершенно стандартной возможности СУБД — индекса, а потом героически написали фактически свой планировщик запроса на SQL, чтобы получить хоть сколь-нибудь эффективную выборку на тех возможностях, что у них остались.
Там в первом же абзаце написано, что опции изменить приложение или дизайн базы у них не было, так что пришлось пораскинуть мозгами. В результате они устранили аварийное завершение запросов по таймауту на вебсервисе, и запрос стал выполняться за доли секунды. Кстати, они консультировались на IRC канале #postgresql с экспертами.
Так часто бывает у приглашённых консультантов, я и сам оказывался в такой ситуации не раз. Помню как на большом проекте OeBS ужасно тупил Oracle Application Server (конкретно его компонент Concurrent Program Manager), и не было совершенно никакой возможности исправить SQL запрос внутри исполнимого файла сервера (бинарника), который постоянно нагружал базу и вылезал в топ AWR. Проблему решили при помощи stored outlines (это коллекция сохранённых хинтов оптимизатора для конкретного хэша запроса). Сотрудники Oracle подтвердили что других вариантов нет, и патч для сервера выпускать не захотели.
А у нас в канадонии и в зооаптеке без рецепта никак.
Нет тут никаких болячек. Любой версионник тоже блокирует измененные строки, но при этом он не мешает читающим транзакциям видеть предыдущие версии строк (снэпшоты). А вот другие модифицирующие транзакции, если попытаются изменить те же самые строки, вынуждены будут подождать, пока первая транзакция не завершится и не "отпустит" их, и лишь затем смогут продолжать работу.
Статья напоминает о том, что порядок обработки строк в общем случае непредсказуем, и часто зависит от физического расположения строк в блоках на диске. И если 2 параллельные сессиии возьмутся обновлять одни и те же наборы строк, то мы можем получить взаимоблокировку.
Это классическая проблема, и автор в данной статье приводит её хрестоматийное решение. Многие новички сталкиваются с этим, и ломают голову потому что не понимают как работает СУБД.
Спасибо за ваши статьи, @Kilor :)
Мне кажется, банковская карта нужна чтобы подтвердить вашу личность. Мало ли что вы там установите на этих серверах? Ограничений ведь никаких. Поэтому, видимо, не всякая карта им подходит.
Оракл рулит, я уже давно таким аккаунтом пользуюсь, всё очень круто.
Великолепно! Большое спасибо, Кирилл.
К слову сказать, эти операторы
pivotиunpivotпоявились впервые в Oracle DB 11g (2007). Позже они были реализованы и в MS SQL Server.В бесплатном PostgreSQL с незапамятных времён есть функция
crosstab(), реализующая то же самое (находится в модулеtablefunc).В MySQL конечно же это не завезли, но ничего страшного, ведь используя обычный SQL без всяких волшебных операторов можно легко получить тот же результат при помощи агрегации с
case, в любой СУБД.Неплохо было бы упомянуть, что Hash Join и Merge Join используются только для соединений с условием равенства (a.col1 = b.col2). Иначе только Nested Loops, он универсальный и годится для любых условий.
Реально достал уже этот детсад. Поставил минус посту. Открываешь почитать тематическую ленту после тяжёлого трудового дня, и видишь этот бред с картинками. Люди с цветными линзами от телескопа вместо глаз.
Во первых, я бы рекомендовал захинтовать вставку при помощи APPEND NOLOGGING, чтоб ускорить и не генерить redo для этих данных. А ещё покурите асинхронный коммит, например https://www.orafaq.com/node/93. Я вижу у вас партиции, следовательно это решение предназначено для прода а не для разработки.
А не лучше ли в таком случае вместо хранения логов в базе слать их во внешнюю систему? Можно написать простейший Java source пакетик (или или готовый байткод загрузить в базу), и через него стримить наши логи в Apache Kafka или в любую другую шину? Оттуда направлять это куда душе угодно, в любую time-series database, или в старый добрый Prometheus, потом их можно будет видеть в системе мониторинга вкупе с остальными метриками и делать выводы, например в Grafana Loki. Заодно и retention policy для логов проще управлять. И можно алерты настроить чтоб по мейлу или прям в телегу получать важные оповещения.
Совершенно верно. За исключением случая #2, но таких клиентов меньшинство.
Я пользуюсь виртуальными номерами. В чём разница в приёме sms и звонка на такой номер? Как это повышает безопасность?
Действительно, появились :)
AdoptOpenJDK?
Странно, в списке shapes нету 1 GB RAM always free машины, самая мелкая "VM.Standard.E2.1" 8 GB RAM. Ищу во вкладке "Specialty and Legacy", где она должна быть по идее. Может это от региона зависит? Хотя в справке написано что для моего региона always free VM доступны.
Да, похоже вы правы, действительно, работает! Возможно, это послабление было сделано специально, по каким-то неизвестным нам причинам, и открывать тикет навряд ли стоит, потому что обратная совместимость важнее и всё такое. Я точно знаю по опыту работы с другими СУБД что этот constraint необходим, и иногда даже задаю этот вопрос на собеседованиях.
В теории реляционных баз данных для внешнего ключа обязателен потенциальный ключ в родительском отношении. Одно из свойств потенциального ключа — это его уникальность.
Согласитесь, что ключи и индексы — это совершенно разные вещи. Ключи обеспечивают целостность и непротиворечивость данных с точки зрения бизнес правил, в то время как индексы — это чисто техническая вещь для ускорения доступа к данным. Как говорится, мухи отдельно, котлеты отдельно. Ключ должен ссылаться на ключ, мы связываем ограничения целостности друг с другом.
В общем случае индекс не обязан присутствовать для поддержки уникального ограничения, но крайне желателен для больших таблиц во избежание full/seq-scan. Для маленьких табличек он точно не нужен, и в других СУБД индекс не создаётся автоматически при создании уникального ключа.
Так что с документацией всё нормально, она просто следует общеизвестным базовым правилам. А вот реализация немножко кривая.
Спасибо за отличную статью! Хотел прояснить одну вещь.
Ответ очень простой: на ограничения уникальности можно ссылаться из внешних ключей. Просто индекса в этом случае недостаточно. Читаем документацию:
Попутно у некоторых людей возникает вопрос: а в чём тогда отличие первичных ключей от уникальных? Ответ: первичный ключ не допускает значений NULL, и он лишь один на таблицу.
Вот еще классная книга, очень рекомендую: "The Internals of PostgreSQL".
Глава про буферный кэш: http://www.interdb.jp/pg/pgsql08.html
Там в первом же абзаце написано, что опции изменить приложение или дизайн базы у них не было, так что пришлось пораскинуть мозгами. В результате они устранили аварийное завершение запросов по таймауту на вебсервисе, и запрос стал выполняться за доли секунды. Кстати, они консультировались на IRC канале #postgresql с экспертами.
Так часто бывает у приглашённых консультантов, я и сам оказывался в такой ситуации не раз. Помню как на большом проекте OeBS ужасно тупил Oracle Application Server (конкретно его компонент Concurrent Program Manager), и не было совершенно никакой возможности исправить SQL запрос внутри исполнимого файла сервера (бинарника), который постоянно нагружал базу и вылезал в топ AWR. Проблему решили при помощи stored outlines (это коллекция сохранённых хинтов оптимизатора для конкретного хэша запроса). Сотрудники Oracle подтвердили что других вариантов нет, и патч для сервера выпускать не захотели.
Бывает что нужно именно по шагам расписать весь алгоритм получения данных. Вот хороший пример (для Postgres, но это сути не меняет):
https://www.endpoint.com/blog/2020/10/02/postgresql-binary-search-correlated-data-cte
Так и сделаю, спасибо ещё раз!