ничем не отличаются?
                  
                  
                  
                  
                  
                  отличия проявляются только у пишущих
                  
                  
                
Тогда отличаются — технически, на RR не используются SIRead locks. К каким отличиям в их поведении это приводит — см. https://wiki.postgresql.org/wiki/SSI#Rollover Да, в PostgreSQL есть специальный режим BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE;, в котором после того, как PostgreSQL гарантировал, что аномалии от этого невозможны, транзакции "внутри" работают точно так же, как на RR (не используют SIRead locks вообще).
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  я этот пример воспроизвёл на постгресе. Т1 упала при коммите…
 я этот пример воспроизвёл на постгресе. Т1 упала п...
                      
                      я этот пример воспроизвёл на постгресе. Т1 упала п...
                    Какой именно из обсуждавшихся? Или прямо тот, что по ссылке?
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Лог двух сессий: /* Session1 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T1 /* Session1 */ UPDATE rollover SET n = n + (SELECT n FROM rollover WHERE id = 2) WHERE id = 1; /* Session2 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T2 /* Session2 */ UPDATE rollover SET n = n + 1 WHERE id = 2; /* Session2 */ COMMIT; /* Session2 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY; -- T3 SELECT count(*) FROM pg_class; /* Session1 */ COMMIT; /* Session2 */ SELECT n FROM rollover WHERE id IN (1, 2); -- Получаю: ERROR: could not serialize access due to read/write dependencies among transactions DETAIL: Reason code: Canceled on conflict out to pivot 11820632, during read. HINT: The transaction might succeed if retried. Всё 1:1 как написано — проверяйте, что Вы делаете не так.
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  1:1 всё так сделаю. скрины ж привёл
У Вас не видно последовательности и сессий на этих screenshots. Прямо скопируйте то, что я показал, в две сессии какого-то клиента (ну или копируйте в psql по одному), и выполните соответствующие запросы по одному, внимательно. > укажите свою версию 15.4. Но это обязано так работать (на последних minors), начиная с 9.1 — это простейший тест.
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  какая должна быть последовательность сессий? у меня обе сессии были открыты ещё до создания таблицы тестируемой а потом порядок транзакций точно такой же, как по ссылке версия у меня тоже PostgreSQL 15.4 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 12.2.1_git20220924-r10) 12.2.1 20220924, 64-bit
У меня же указана, какая — вот, указал для каждого запроса. > у меня обе сессии были открыты ещё до создания таблицы тестируемой Это не имеет значения — главное, чтобы открытых транзакций в них не было (и "забытых" паралелльных транзакций, в которых Вы это же тестировали — тоже, а то мало ли... ;) ). > а потом порядок транзакций точно такой же, как по ссылке Ну вот и посмотрите, как это должно работать (и у меня работает) при таком порядке. Да попробуйте ещё раз с самого начала (выполните DROP этой таблицы), что тут думать. ;)
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  ёёпт:) я сейчас удалю весь контейнер для эксперимента, в абсолютно пустой базе создам таблу и сделаю как в ссылке, посмотрим. upd: скачал, на всякий случай для справки указываю что получил WARNING: there is no transaction in progress то есть в исходный момент 0 транзакций в обеих сессиях
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  в общем, если хоть в Т1, хоть в Т2 после обновления прочитать эти данные, а потом закоммитить — падает именно Т1
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  у Т3 же снепшот берётся в момент выполнения select count(*) from pg_class; ?
WARNING: there is no transaction in progress Нет, стоп. ;) Этого Вы не должны видеть (это будет, если выдать COMMIT; или ROLLBACK; в сессию, где нет активной транзакции).
Ну так сам пример у Вас воспроизводится правильно, так?
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  > Этого Вы не должны видеть (это будет, если выдать COMMIT; или ROLLBACK; в сессию, где нет активной транзакции). ну я так и сделал. чтоб продемонстрировать что активных транзакций не было (вы выше предполагали что я мб чёт забыл закрыть)
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  да. но почему чтение после обновления всё ломает — мне непонятно моменты взятия снепшотов у всех трёх транзакций вроде бы остаются теми же, чтение ничего не меняет (казалось бы). неясно. в общем, в сообщении со скриншотами всё правильно просто это не 1 в 1 как по ссылке. отличается на лишний читающий запрос вот взглянув на эти скрины (последовательность тоже указал верно в сообщении) — можете ответить в чём дело, почему поведение меняется
> в общем, в сообщении со скриншотами всё правильно > просто это не 1 в 1 как по ссылке. Вот же ж... а я подумал, что у Вас не работает исходный пример. А Вы можете расписать то, что Вы делаете, аналогично тому, как писал я (со screenshots я перепечатывать не собираюсь, извините)?
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  вы можете не перепечатывать а просто в Т1 после апдейта добавить чтение всей таблице. и то же самое в Т2 тоже после апдейта 95% кода у вас уже есть (он взят из примера по ссылке)
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  ``` /* Session1 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T1 /* Session1 */ UPDATE rollover SET n = n + (SELECT n FROM rollover WHERE id = 2) WHERE id = 1; /* Session1 */ select * from rollover ; /* Session2 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T2 /* Session2 */ UPDATE rollover SET n = n + 1 WHERE id = 2; /* Session2 */ select * from rollover ; /* Session2 */ COMMIT; /* Session2 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY; -- T3 /* Session2 */ SELECT count(*) FROM pg_class; /* Session1 */ COMMIT; /* Session1 */ ERROR: could not serialize access due to read/write dependencies among transactions DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt. HINT: The transaction might succeed if retried. ```
Во-первых, заметьте, что тут не нужна T3 (то же самое получается). Во-вторых... мы же уже обсуждали именно этот случай, или мне кажется? Ладно, как бы там ни было... /* Session1 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T1 /* Session1 */ UPDATE rollover SET n = n + (SELECT n FROM rollover WHERE id = 2) WHERE id = 1; /* Session1 */ SELECT * FROM rollover; /* Session2 */ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- T2 /* Session2 */ UPDATE rollover SET n = n + 1 WHERE id = 2; /* Session2 */ SELECT * FROM rollover; /* Session2 */ COMMIT; /* Session1 */ COMMIT; Допустимые расписания (как и то, что каждая транзакция должна видеть при чтении после UPDATE): T1 T2 1. (1, 100), (2, 10) ----> (1, 110), (2, 10) ----> (1, 110), (2, 11) T2 T1 2. (1, 100), (2, 10) ----> (1, 100), (2, 11) ----> (1, 111), (2, 11) Так вот если разрешить выполнение по этому сценарию, то (несмотря на совпадение конечного результата с первым расписанием), транзакции будут видеть после своих update следующее: T1: (1, 110), (2, 10) T2: (1, 100), (2, 11) и ни одному из этих расписаний такое не соответствует — поэтому первую PostgreSQL откатывает.
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  то есть опять банальное раскладывание по возможным комбинациям очерёдности даёт все ответы…
Естественно, оно всегда даёт все ответы. :) Да, кстати, я вот в прошлый раз написал, что поиск цикла в графе предшествования — это просто shortcut. Но это не совсем так, т.е. это так только для того человека, который анализирует/проверяет сериализуемость — а алгоритмы обеспечения serializability как раз и строятся на предотвращении либо поиске (и разрыве, путём отката транзакций) таких циклов (или характерных для них структур, как это делает SSI) — потому что в несериализуемых расписаниях они неизбежно будут.
 RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          RAFIZ
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Обсуждают сегодня