• Блокировки в PostgreSQL: 4. Блокировки в памяти
    0
    Вместо этого ядро должно давать точную информацию о том, какие ожидания были у сеанса, сколько их было и сколько времени они заняли


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

    Кажется, что это достаточно большой и сложный модуль и возможно на его написание нет ресурсов.
  • Блокировки в PostgreSQL: 4. Блокировки в памяти
    +1
    Егор, спасибо за отличный цикл статей. Очень ждем следующего цикла :)

    Вопрос скорее не про блокировки а в целом про экосистему PostgreSQL

    К сожалению, единственная доступная информация об ожиданиях — информация на текущий момент. Никакой накопленной статистики не ведется. Единственный способ получить картину ожиданий во времени — семплирование состояния представления с определенным интервалом. Встроенных средств для этого не предусмотрено


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

    Я к тому, что для OLTP эта ситуация типична. Как так получилось, что в PostgreSQL до сих пор нет встроенных средств семплирования, которые позволят хоть как-то отловить подобные запросы? Либо все-таки подобные запросы не настолько сильно вредят Postgres, и поэтому семплирование неприоритетно. То есть блокировки, которые Вы предложили отловить семплированием — тоже редкий случай, не стоящий того, чтобы инструменты семплирования размещать в ядро.

    Либо принципиально такие инструменты как семплирование — это не задача PostgreSQL и их некорректно встраивать. Было бы интересно услышать Ваше мнение по этому вопросу.
  • Блокировки в PostgreSQL: 3. Блокировки других объектов
    0
    Немного смешалось 2 кейса, поэтому описание получилось расплывчатым. Изначально я забыл (или тогда еще не знал) о существовании частичного индекса и сделал с Redlock.

    Затем появился кейс запрета параллельных действий пользователя. Приведенным Вами описанием выше это тоже можно решить, при условии, что каждое действие пишется в таблицу событий. А это так и есть. Спасибо. Кстати, еще один аргумент в пользу необходимости в проекте такой вот таблицы событий. Для rate limiters можно очень успешно использовать без необходимости REDIS
  • Блокировки в PostgreSQL: 3. Блокировки других объектов
    0
    Я понял, спасибо. Принцип в том, чтобы упорядоченность соблюдалась в рамках страницы, а не в порядке следования строк в этой странице
  • Блокировки в PostgreSQL: 3. Блокировки других объектов
    0
    Да, все верно.

    Изначально была сделана просто вставка событий id + JSONB. Среди этих событий было голосование за публикации. Конечно, в итоге была сделана отдельная таблица для событий голосования с подходящим уникальным индексом. Но до этого, в качестве быстрого решения была сделана распределенная блокировка на REDIS. Она впоследствии осталась для соблюдения условия «пользователь может сделать только одно социальное действие (голосование либо публикацию комментария и т.п.)», чтобы усложнить написания злоумышленниками скрипта, который будет от лица пользователя делать множество запросов (лайков, например) параллельно.

    А можно было бы сделать это на рекомендательных блокировках? Например заблокировать id пользователя (или хеш от него)
  • Блокировки в PostgreSQL: 3. Блокировки других объектов
    +1
    Рекомендательные блокировки

    В приведенном примере блокировка действует до конца сеанса, а не транзакции, как обычно.


    У меня был случай, когда в силу недостатков архитектуры нельзя было явно поставить уникальность на вставку нового значения. Чтобы защититься от дубликатов, я реализовал REDIS lock. Перед тем как осуществить действие, происходит попытка захвата блокировки действия. После успешного завершения действия (или ошибки) — блокировка снимается. Или же она снимается по таймауту.

    Получается, что вместо этого можно было бы использовать рекомендательные блокировки? Заблокировать условный ресурс и быть уверенным, что другой сеанс будет ждать освобождения ресурса? Разве что кажется, что есть недостаток. Если сеанс внезапно завершается (обрывается соединение по какой то причине, если я понимаю правильно, что такое сеанс) — то блокировка мгновенно опускается. С другой стороны, раз блокировки нет, то действие откатилось и вроде все хорошо.

    Однако как быть, если сеанс зависнет и блокировка тоже застрянет? Тут тогда таймаут снятия блокировки будет равен таймауту завершения сеанса?
  • Блокировки в PostgreSQL: 3. Блокировки других объектов
    +1
    Егор, читаю (по 2 раза минимум, для глубокого понимания) все ваши статьи, но к сожалению, времени стало намного меньше, поэтому перестал задавать вопросы. Но по этой статье все таки задам :)

    Раньше таблицы расширялись только на одну страницу за раз. Это вызывало проблемы при одновременной вставке строк несколькими процессами, поэтому в версии PostgreSQL 9.6 сделали так, чтобы к таблицам добавлялось сразу несколько страниц (пропорционально числу ожидающих блокировку процессов, но не более 512).


    Интересен тогда кейс append-only:
    * Пусть у нас идет интенсивная вставка значений в таблицу, допустим 1000 строк в секунду.
    * Пусть так получилось, что это не batch — именно 1000 в секунду, причем это делают разные процессы. Извиняюсь за натянутость кейса, он специально преувеличен, чтобы понять суть.
    * Пусть строки достаточно «тяжелые».

    То есть вероятен описанный выше кейс, когда разные процессы начнут расширять таблицу на новую страницу. Пусть мы достигли предела и расширились на 512 страниц за раз из разных процессов.
    А потом продолжили вставку новых значений (она не останавливалась).

    Значит ли это все, что строки будут лежать в файлах сильно фрагментировано? То есть мы ожидаем append-only и вставку «строка за строкой, id за id». А из за такого вот расширения упорядоченность строк будет сильно нарушена. Что, в частности, помешает эффективному использованию индекса BRIN
  • WAL в PostgreSQL: 3. Контрольная точка
    0
    А в чем было дело? Очень интересно, может быть какой-то интересный кейс тюнинга?
  • WAL в PostgreSQL: 3. Контрольная точка
    0
    Если я все правильно понял, контрольная точка не пишет на максимальной скорости в том числе и потому, чтобы не расходовать железные ресурсы. При необходимости ускорения железные ресурсы начнут больше расходоваться и можно «неожиданно» получить деградацию производительности. То есть цена ускорения это всегда потенциальная деградация?

    Или алгоритм настолько умен, что даже рост нагрузки за счет ускорения можно прогнозировать? Вернее, есть параметр, ограничивающий его ресурсы, который я упустил, когда читал статью
  • WAL в PostgreSQL: 3. Контрольная точка
    0
    Очень заинтересовал момент доступности страницы для чтения при pin :)

    А если страница вытесняется на диск с целью заменить ее на новую с диска (все страницы буффера заняты, требуется вытеснение)? В этом случае «можно читать» вероятно, не работает, потому что содержимое страницы в какой-то момент полностью будет изменено.
  • WAL в PostgreSQL: 3. Контрольная точка
    +1
    Блокируют ли грязную буфферную страницу процессы checkpointer/background writer перед записью ее на диск?
  • WAL в PostgreSQL: 3. Контрольная точка
    +1
    В заключение все нежурналируемые таблицы перезаписываются с помощью образов в init-файлах.


    имеются ввиду слои init, которые остались на диске на момент отказа системы? Могут ли они быть повреждены, ведь они могут быть в неконсистентном состоянии (на то и WAL для других операций)
  • WAL в PostgreSQL: 3. Контрольная точка
    +1
    Надо просто продолжить выполнение текущей, но ускориться.


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

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

    Правильно ли я понял, что процесс checkpointer это популярный кандидат (один из кандидатов) на оптимизацию, если вдруг система «ни с того ни с сего» начала работать медленнее?
  • WAL в PostgreSQL: 2. Журнал предзаписи
    +1
    Егор, спасибо за отличную статью. Вопрос, связанный с заморозкой.

    В заголовке фрагмента WAL хранится:
    номер транзакции, к которой относится запись;

    полагаю, что этот номер для чего-то используется, например, при восстановлении.

    Но как быть если номер транзакции заморожен, прошло уже много времени и в системе появилась уже другая транзакция, номер которой совпадает с замороженным номером?

    Как в целом процесс заморозки дружит с WAL с точки зрения номеров транзакций?
  • WAL в PostgreSQL: 1. Буферный кеш
    +1
    Спасибо, а как происходит освобождение «уже ненужного» буфферного кольца. Буфферы, ранее выделенные на кольцо, полностью очищаются? Ведь насколько я понял трудно будет «убрать кольцо и сделать буфферы кольца доступными для всех», ведь буферы кольца узко специализированы были под конкретный массовый оператор. И врят ли будут полезны другим транзакциям.
  • WAL в PostgreSQL: 1. Буферный кеш
    +1
    Алгоритм clock-sweep перебирает по кругу все буферы (используя указатель на «следующую жертву»), уменьшая на единицу их счетчики обращений.


    Вопрос 1 — Правильно ли я понял, что:
    * Вытеснение начинается только когда нет свободных буферов, а в буферы надо поднять страницу
    * Алгоритм уменьшает счетчики буферам, «которым не повезло оказаться до буфера с нулевым счетчиком». Потому что как только алгоритм находит буфер с нулевым счетчиком — он его вытесняет, а последующие буферы уже не трогает.
    * То есть скорость пробегания полного круга существенно зависит от количества «уже нулевых счетчиков» на пути алгоритма.

    Размышления:
    На первый взгляд кажется, что было бы неплохо иметь хеш таблицу с указателем на буферы с нулевыми счетчиками, чтобы при необходимости вытеснения сначала сразу же вытеснять их и не трогать другие буферы, которым «не посчастливилось оказаться до нулевого буфера».

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

    Тут конечно сразу же недостаток — при увеличении счетчика надо как то нулевые буферы из хеш таблицы убирать.

    Вопрос 2 — Правильно ли я понял, что алгоритм вытеснения выполняет 2 задачи сразу
    * Уменьшает счетчики
    * Вытесняет нулевые буферы

    Вопрос 3 — Фоновый процесс записи грязных страниц на диск. Использует ли он как-то информацию о счетчиках обращений?
  • WAL в PostgreSQL: 1. Буферный кеш
    +1
    А насколько переход на directIO способен увеличить производительность? Действительно ли если постгрес возьмет на себя часть функций ОС — это будет хорошим решением? Не идем ли мы таким образом в сторону, когда постгрес — это и есть операционная система, ведь она берет часть ее функций на себя.

    И это может значительно замедлить скорость развития самой Постгрес.

    UPD. На ум пока приходит выделять отдельный мощный сервер под постгрес таким образом, чтобы бОльшая часть RAM была занята файловым кешем и буфферным пулом. Тогда условно говоря файловый кеш ОС будет работать почти исключительно на нужды Постгрес.
  • WAL в PostgreSQL: 1. Буферный кеш
    0
    При операциях, выполняющих массовое чтение или запись данных, есть опасность быстрого вытеснения полезных страниц из буферного кеша «одноразовыми» данными.


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

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


    Расскажите, пожалуйста, поподробнее, для каких операций выделяются буфферные кольца. Интересная мысль возникла — если буфферное кольцо — это хорошая идея, то «хватит ли всем желающим» буфферных колец? Может ли такое получиться, что буфферные кольца займут весь буффер или значительную его часть, и остальным операциям «придется тесниться» на малом количестве оставшихся без колец буфферов?
  • WAL в PostgreSQL: 1. Буферный кеш
    +1
    Егор, очень рад продолжению цикла статей, спасибо за труд.

    Интересное подозрение возникло при чтении особенностей вытеснения.
    1. Пусть нужно прочитать страницу в буфферный пул с целью ее изменить — например, добавить новую строку в таблицу
    2. Находим свободный слот и пусть этот слот был последним из свободных. Пишем страницу в него.
    3. Изменяем страницу — добавляем строку. Отпускаем buffer pin блокировку.
    4. Счетчик буфферного слота стал равен 1. Может и больше, но тут важен момент что страница «свежая» и счетчик «маленький»

    И получается следущий интересный момент. Я всегда предполагал, что вытеснять нужно «старые» слоты, к которым уже давно нет обращений. Но для «свежих» буферов это получается не так. То есть свежезаписанные буфферы имеют те же шансы выжить, что и «старые» буфферы, счетчик которых мал, потому что к ним действительно долго не обращались.

    На мой взгляд это «немного нечестно» для буферов-новичков. Это все равно что условно говоря на бирже фрилансеров банить новичков за то, что у них «давно не было заказов».

    Прошу прощения за такое нетехническое сравнение, но я таким образом попытался передать свою мысль. Если чуть более технически написать — если идет работа с очень большими потоками данных, то «новичков» будут сразу же «вымывать» из буфферов. А это может быть не то, что нужно системе для производительной работы.

    На ум приходит идея дать «буферам-новичкам» бонус в виде базового значения счетчика не 1 а например 5.
  • MVCC в PostgreSQL-8. Заморозка
    +1
    Егор, большое Вам спасибо за отличный цикл статей. И самое главное — отдельное спасибо за обратную связь, ответы на вопросы. С нетерпением жду новых статей.

    Я изучал заморозку по курсу на сайте postgrespro и к сожалению не понял, на мой взгляд, очень важный момент.

    Чтобы не допустить таких «путешествий» из прошлого в будущее, процесс очистки (помимо освобождения места в страницах) выполняет еще одну задачу. Он находит достаточно старые и «холодные» версии строк (которые видны во всех снимках и изменение которых уже маловероятно) и специальным образом помечает — «замораживает» — их


    Заморозку можно вызвать вручную командой VACUUM FREEZE — при этом будут заморожены все версии строк, без оглядки на возраст транзакций


    * То есть, у этой строки установлено 2 бита — бит фиксации и бит отмены
    * Пусть все-таки строку начала менять транзакция.
    * устанавливается xmax
    * снимаются биты — фиксации и отмены, потому что они используются в MVCC
    * xmin начинает уже иметь значение — с какой транзакции строка видна.

    Как быть? ведь xmin уже полностью нерелевантен, но его надо использовать для видимости.
    Думаю, что его надо каким-то числом перезаписать или установить еще какие-то некие служебные биты, чтобы «на xmin никто не обращал внимания».

    Подскажите, пожалуйста, что происходит в данной ситуации. Можно было бы, конечно, происследовать вопрос самостоятельно, но это непросто, когда нет точки, от которой можно оттолкнуться.
  • MVCC-7. Автоочистка
    +1
    Запустившись, рабочий процесс подключается к указанной ему базе данных и начинает с того, что строит список:
    всех таблиц, материализованных представлений и toast-таблиц, требующих очистки,


    И снова вопрос про TOAST, немного не в тему статьи
    * Пусть в таблице есть 2 поля — JSONB и TEXT.
    * Пусть есть строки, в которых содержатся достаточно крупные значения в этих полях, чтобы работал TOAST
    * берем одну из строк
    * меняем один символ в JSONB, например в поле number_of_posts было значение 1, а стало — 2.
    * Создается ли новая версия TOAST только для JSONB? То есть TOAST это таблица, где данные хранятся в виде ключ-значение?
    И каждой строке основной таблицы соответствует 2 строки TOAST таблицы (на каждое из полей)?
  • MVCC-7. Автоочистка
    +1
    Очистка не блокирует другие процессы, поскольку работает постранично


    Но она работает с буфферным кешем? То есть закрепляет страницы буфферного кеша + ставит физическую блокировку, чтобы
    работать со страницей эксклюзивно. То есть получается, что блокировка все таки есть, если я все правильно понял.
  • MVCC-7. Автоочистка
    +1
    С автоанализом дело обстоит примерно так же. Считается, что анализа требуют ту таблицы, у которых число измененных (с момента прошлого анализа) версий строк превышает пороговое значение


    А где хранится информация о том, когда именно была изменена строка?
    * Запоминается дата последнего анализа
    * Как именно выбрираются строки, которые изменились после? Вероятно, запоминается xmax (или горизонт событий), а не сама дата. И мониторится
    разница (дельта) между горизонтом событий и последней транзакцией, которая относится к таблице. Верно?
  • MVCC-7. Автоочистка
    +1
    Число мертвых версий постоянно собирается коллектором статистики


    Анализ таблиц, который осуществляет AUTOVACUUM и коллектор статистики — это разные процессы?
  • MVCC-7. Автоочистка
    +1
    Егор, спасибо за статью и отдельное спасибо за темп 1 статья в неделю. Такой темп непросто выдерживать, поэтому вдвойне благодарен. Традиционные вопросы.

    Процесс autovacuum launcher составляет список баз данных, в которых есть какая-либо активность. Активность определяется по статистике, а чтобы она собиралась, должен быть установлен параметр track_counts. Никогда не выключайте autovacuum и track_counts, иначе автоочистка не будет работать.


    Получается, есть еще какой-то фоновый сборщик статистики? Потому что автовакуум сам по себе собирает статистику.
    Вероятно не получится так, что на основе своей же статистики он решает когда запускать сбор статистики.
  • MVCC-6. Очистка
    0
    Еще вариант: длинные транзакции заранее планируются и запускаются по расписанию. Но тут нужно участие DBA — хотелось бы этого избежать тоже
  • MVCC-6. Очистка
    0
    Я немного расплывчато сформулировал кейс. Он такой:
    * Пусть решили сделать «отчетную» реплику по просьбе аналитиков (и чтобы они нам не грузили мастер).
    * Создали отдельного читающего юзера для всех аналитиков, поставили уровень изоляции Repeatable Read для согласованности, раздали логин-пароль (один на всех)
    * Аналитики начали экспериментировать, строить свои отчеты.
    * И вот аналитик Вася запускает отчет на таблице orders, длительность которого 3 часа.
    * Реплика начала отставать все больше и больше с каждым часом, потому что запрос Васи затронул очень много данных в таблице orders.
    * Вася не подозревал что получится такой долгий запрос и терпеливо решил подождать.
    * Аналитик Петя решил посмотреть данные за последний час, он предполагает что данные актуальны и не знает о запросе Васи.
    * Аналитик Петя строит аггрегаты, получает результат, не подозревая, что он пользуется устаревшими данными.
    * И не дай бог это некий отчет, который будет использоваться при финансовых расчетах.

    Если я все правильно понял, такая ситуация вполне имеет место быть.

    Получается, что придется делать вот такое:
    * Мониторим отставание (само собой)
    * Учим аналитиков как смотреть свежесть данных, выводим им где-то например текущее оставание реплики в админке
    * Учим аналитиков смотреть текущие транзакции, помогаем отследить «ждунов» — запускающих слишком длинные транзакции без согласования с остальными.
    * Бедным аналитикам приходится кооперироваться между собой в чатиках, составлять расписания «длинных выгрузок» и т.п.

    Очень неудобно. Как вариант можно сделать «отчетную реплику для коротких запросов» и «отчетную тормозящую реплику» для длинных. И даже может «финансовую реплику» куда ходить будут строго по расписанию.

    Как Вам такая идея? Может есть идея получше? Кейс очень актуальный.

    Сорри, что немного не в тему статьи
  • MVCC-6. Очистка
    0
    Будет ли мастер хранить сегмент WAL в этом случае до тех пор, пока реплика его себе не накатит?

    Получается затятная ситуация:
    * Очень длинные отчеты нагружают мастер. Только ли тем, что нужно хранить сегменты WAL? Не страдает ли от этого VACUUM, table bloat? Так ли критично то, что сегменты хранятся полдня? Но задержки такие идут скажем на постоянной основе.
    * Очень длинные отчеты конкурируют между собой. Если один аналитик запустил отчет на полдня, то другие должны учитывать, что не могут получить актуальные данные в этот период.

    Тогда получается, что нужно делать даже 2 реплики — одну для очень долгих отчетов, другую — для отчетов но покороче.
  • MVCC-6. Очистка
    +1
    Однако надо понимать, что кластеризация не поддерживается: при последующих изменениях таблицы физический порядок версий строк будет нарушаться.


    О команде CLUSTER очень часто упоминают и постоянно критикуют ее за то, что ее эффект «выдыхается» (в силу MVCC) и за то, что она блокирует все.

    Когда все-таки ее целесообразно использовать?
  • MVCC-6. Очистка
    +1
    Егор, большое спасибо за очередную отличную статью! Вопросы :)

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


    Но при этом физически они выглядят одинаково. Пусть на мастере совершилась очистка а на реплике идет отчетная транзакция, которая завершится через пару часов условно.

    WAL sender отправляет сегмент, где страницы уже очищены. Реплика не будет его накатывать, пока транзакция не завершится? И все остальные сегменты тоже выстроятся в очередь.

    Если так то отчетная реплика может существенно отставать от мастера
  • MVCC-5. Внутристраничная очистка и HOT
    0
    Цитата из статьи

    TOAST-таблица используется только при обращении к «длинному» значению. Кроме того, для toast-таблицы поддерживается своя версионность: если обновление данных не затрагивает «длинное» значение, новая версия строки будет ссылаться на то же самое значение в TOAST-таблице — это экономит место.


    А если происходит обратная ситуация — меняется только «длинное значение»? Что происходит? Создается новая версия строки, по сути, копия уже существующей с той лишь разницей, что ссылка будет указывать на новую версию TOAST-таблицы?

    Если так, то понятно, как будет работать HOT в данном случае. Если нет — поясните, пожалуйста, механизм с TOAST.
  • MVCC-5. Внутристраничная очистка и HOT
    +1
    Вероятно, следующий вопрос слишком низкоуровневый — а как фоновый AUTO VACUUM и внутристраничная очистка «делят между собой» процесс очистки? Пусть автовакуум хочет удалить цепочку, а начавшаяся внутристраничная очистка хочет цепочку продолжить.

    Что будет происходить? Вероятно, ситуация решается физическими блокировками страниц?
  • MVCC-5. Внутристраничная очистка и HOT
    +1
    Внутристраничная очистка и VACUUM

    Получается, что последующая процесс AUTO VACUUM почистит индексные страницы и уберет unused указатели? А также удалит цепочку.
  • MVCC-5. Внутристраничная очистка и HOT
    +1
    Все неактуальные версии строк (0,1), (0,2) и (0,3) очищены; после этого на освободившееся место добавлена новая версия строки (0,5).


    Ради интереса я выполнил UPDATE в транзакции и потом откатил транзакцию. Строки все равно остались очищенными. То есть внутристраничная очистка от транзакции, видимо, никак не зависит. Как и проставление битов статусов транзакций. То есть, такие операции нетранзакционны, видимо, в силу того, что такая транзакционность никогда не требуется.
  • MVCC-5. Внутристраничная очистка и HOT
    +1
    Егор, спасибо за статью. Особенно интересна рекомендация про fulfill фактор как возможность оптимизации производительности. Надеюсь, выпадет случай применить ее на практике.

    Так как Вам удобнее отвечать на вопросы в отдельных комментариях — напишу их также отдельно.

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


    Пусть изменилось поле text, которое настолько велико, что хранится в TOAST. Пусть его изменили несколько раз. Началась внутристраничная очистка. Полагаю, что для TOAST она не работает? Потому что TOAST — это размещение данных на нескольких страницах.

    применяется ли MVCC к TOAST? Вероятно, это будет раскрыто в последующих статьях и вопрос преждевременный.
  • MVCC-4. Снимки данных
    0

    Спасибо, а как пул соединений поможет в данном случае? Насколько я понял, источник информации о состоянии транзакций «один на всех»

  • MVCC-4. Снимки данных
    +1
    Егор, большое спасибо за статью!

    Традиционно, несколько вопросов:

    №1.
    На уровне изоляции Read Committed снимок создается в начале каждого оператора транзакции. Такой снимок активен, пока выполняется оператор.


    То есть имеем операции «создания»/«удаления» снимка. Их тем больше, чем больше операторов в транзакции

    На уровнях Repeatable Read и Serializable снимок создается один раз в начале первого оператора транзакции. Такой снимок остается активным до самого конца транзакции.


    То есть имеем всего одну операцию «создания»/«удаления» снимка.

    Сам вопрос: Насколько затратны операции «создания»/«удаления»? Можно ли сказать, что уровни Repeatable Read и Serializable
    значительно меньше нагружают сервер БД? Или разница ничтожно мала по сравнению с другими действиями для этих транзакций? Я имею ввиду порядки затрат, соизмеримые с порядками затрат оптимизатора, то есть микросекунды. Понятно, что по сравнению с IO операциями передачи данных по сети эти затраты будут ничтожно малы.

    Имеется ввиду затратность по:
    * RAM — насколько «тяжеловесна» информация о снимке.
    * CPU/IO — насколько трудоемко создавать новые снимки (и видимо помечать неактивные к удалению).

    №2.
    На уровне изоляции Read Committed снимок создается в начале каждого оператора транзакции. Такой снимок активен, пока выполняется оператор.


    Что означает понятие «снимок активен» в применении к Read Committed? Это означает, что при создании нового снимка, ранее созданный (например, на момент создания транзакции) уже никак не участвует в транзакции? Как удаляются такие снимки? Они помечаются к удалению или удаляются в рамках той же транзакции?

    №3
    такие интервалы не пересекаются, поэтому одна строка представлена в любом снимке максимум одной своей версией.


    То есть невозможна ситуация, при которой xmin xmax одной и той же строки будут перезаписаны в разных транзакциях? То есть если xmin/xmax когда-либо были записаны — измениться они уже не могут (immutable). При условии, если транзакция изменившая их первой — зафиксировалась.

    №4
    А для DDL-запросов (тоже транзакционны) изоляции и снимки тоже используются? Насколько механизмы изоляций и снимков отличаются от уже описанных механизмов в этой и в предыдущих статьях?
  • MVCC-3. Версии строк
    0
    Пересоздание всех индексов без блокировки: CREATE INDEX CONCURRENTLY «new» + DROP INDEX «old» + ALTER INDEX «new» RENAME TO «old».


    * После подобной процедуры необходимо также запускать проверку целостности индекса, т.к. индекс в CONCURRENTLY режиме может получиться «битый»
    * Не все индексы, думаю, нужно пересоздавать, а только те, которые затронуты были массовыми изменениями

    Причем обе процедуры можно смело делать «на бою» без простоя.


    Эти процедуры могут расходовать ресурсы и таким образом влиять на производительность БД на продакшене. Думаю, выполнять их нужно с осторожностью.

    У меня был случай, когда после массовой операции (вычищение устаревших данных в таблице) только на пересоздании индексов удалось выиграть 100 Гб места на диске.


    Если есть возможность — опишите свой кейс более подробно, будет интересно.
  • MVCC-3. Версии строк
    0
    Теперь немного понятнее стало, почему массовый апдейт даже небольшого числового поля (INTEGER) привел однажды к тому, что индекс «сломался» — эффективность его работы существенно (на порядок) просела и пришлось делать VACUUM FULL (не то написал) перестроение индекса с блокировкой. Кейс к сожалению (или к счастью) не мой. Но что делать и как обновлять — не понятно пока
  • MVCC-3. Версии строк
    0
    На ум приходит ошибочный кейс «чистки БД»:
    * Делаем массовый апдейт description поля типа TEXT, например вычищают XSS injections (или решили ругательные слова заменить точками постфактум, как бывает в стартапах)
    * Сразу получаем минимум 2х к размеру TOAST-таблицы.
    * И это место видимо без FULL VACUUM оказывается очень тяжело высвободить для ОС (и для других таблиц). Даже если обновлять пачками.

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

    Очень хотелось бы прочитать про эту проблему в будущем, потому что я часто слышал кейсы, когда они что-то обновляли массово а потом ломался индекс или место не могли высвободить. И пришлось просто все блокировать и запускать VACUUM FULL. может еще какие то решения есть