Ответ
PostgreSQL не реализует уровень изоляции READ UNCOMMITTED (чтение незафиксированных данных) из-за своей архитектуры MVCC (Multiversion Concurrency Control). В этой модели каждый запрос видит снимок данных (snapshot) на момент своего начала, что физически исключает возможность чтения "грязных" данных из незавершённых транзакций.
Как это работает:
- При любом
SELECTсистема обращается к согласованному снимку, а не к непосредственно изменяемым страницам данных. - Если вы явно укажете
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;, PostgreSQL тихо понизит его доREAD COMMITTED(чтение зафиксированных данных) — минимального доступного уровня.
Пример на C# с Npgsql:
using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
// Попытка установить ReadUncommitted
using var transaction = await connection.BeginTransactionAsync(
IsolationLevel.ReadUncommitted // Будет проигнорирован
);
var command = new NpgsqlCommand("SELECT balance FROM accounts WHERE id = 1", connection, transaction);
var balance = await command.ExecuteScalarAsync();
// Здесь balance будет взят из снимка READ COMMITTED,
// а не из незавершённой транзакции другого пользователя.
Почему это осознанный выбор:
- Целостность данных: Гарантируется, что приложение никогда не прочитает данные, которые могут быть откатаны, что предотвращает логические ошибки.
- Производительность: MVCC позволяет выполнять чтение без блокировок, даже при наличии параллельных пишущих транзакций, что хорошо для OLTP-нагрузки.
- Упрощение модели: Разработчикам не нужно думать о последствиях чтения "грязных" данных, так как этот сценарий невозможен.
Если вам нужно читать данные без ожидания завершения других транзакций, в PostgreSQL для этого используется уровень READ COMMITTED в сочетании с MVCC.
Ответ 18+ 🔞
А, слушай, про PostgreSQL и этот их READ UNCOMMITTED — это вообще отдельная песня, блядь. Так вот, сука, они его в принципе не делают, нахрен не нужен. А почему? Да потому что у них там архитектура, ёпта, MVCC, то есть многоверсионность, блядь. Это ж гениальная штука, если вдуматься.
Представь себе: каждый твой запрос, когда начинается, он как бы фотографирует данные на этот самый момент. Снимок, snapshot, называется. И работает он уже с этой фоткой, а не лезет в живую, сука, базу, где прямо сейчас кто-то пишет, удаляет или хуй знает что творит. Поэтому физически, блядь, прочитать какие-то незавершённые, «грязные» данные — это просто невозможно, как ни старайся. Их нет в этом снимке, они в другом измерении, в рот меня чих-пых!
И вот самый прикол: если ты такой умный и попробуешь в коде явно указать «дайте мне READ UNCOMMITTED», типа:
using var transaction = await connection.BeginTransactionAsync(
IsolationLevel.ReadUncommitted // Будет проигнорирован
);
Так PostgreSQL на тебя посмотрит, вздохнёт и тихонечко, без всяких предупреждений, понизит это до READ COMMITTED. Всё, приехали. Ты думаешь, что живёшь опасно, на грани, а на самом деле у тебя самый базовый, безопасный уровень. Объегорили, короче.
А почему они так сделали? Да потому что нехуй, вот почему! Во-первых, целостность данных, блядь. Чтобы твоё приложение не прочитало какую-нибудь хуйню, которую другая транзакция через секунду откатит, и ты потом с этими данными начнёшь делать какую-то ересь. Во-вторых, производительность. Чтение без блокировок — это же красота! Один пишет, десять читают, и никто никого не ждёт. И в-третьих, простота, ёпта. Разработчику не надо голову ломать, думать: «А не прочту ли я сейчас какую-нибудь дичь?» Не прочтёшь. Расслабься.
Так что если тебе нужно, чтобы SELECT не вис, ожидая, пока кто-то там COMMIT сделает, то в Постгресе и так по умолчанию READ COMMITTED с его MVCC эту проблему решает. Всё уже придумано до нас, мудаков.