
Den
27.08.2017
00:54:42
это да, как минимум
ещё беспокоит, не "сдурит" ли в какой-то прекрасный момент планировщик или оптимизатор? Так-то тесты проходят, конечно...
в общем, с конфликтами более или менее ясно: в cur-е select должен быть for update, а вероятность гонки между select-ом и insert-ом можно свести к минимуму на, так сказать, уровне бизнес-логики.

Fike
27.08.2017
01:35:58

Google

Den
27.08.2017
01:39:31
ну я не очень-то хорошо разбираюсь в потрохах Постгреса.. Может быть, это просто паранойя от незнания :)

Mikhail
27.08.2017
06:43:37
Уважаемые, подскажите пожалуйста, какие подводные камни могут быть в подобном, хмм, странном, варианте: http://lpaste.net/357996
Мне нужно атомарно либо обновить "документ" с сохранением предыдущего значения, либо добавить новый "документ", если его ранее не было. Upsert мне тут не поможет - версия 9.4. Вообще, этот вариант работает и на первый взгляд корректно (там trace, для отладки вставленные, показывают, что лишние "ветки" не исполняются), но всё же немного страшновато.
А вообще, если сие переписать на PlPgSQL в императивном стиле, оно получится куда логичнее, но, по идее, будет сильно менее эффективно.
@verrens , https://www.postgresql.org/docs/9.6/static/plpgsql-control-structures.html
Example 41-2. Exceptions with UPDATE/INSERT
Иначе гонки

Den
27.08.2017
07:19:27
Но ведь гонка тут может быть только одна - между select-ом в cur, не вернувшим ничего, и insert-ом, свалившимся с duplicate?

Yuriy
27.08.2017
07:32:42
SELECT FOR UPDATE или SELECT FOR SHARE, нє ?
Вроди ж как уже 6 лет в спеке ...

Den
27.08.2017
07:34:29
Я уже добавил for update (в ветку cur), буквально сразу после первой публикации:) Вот только от insert-а оно не спасёт

Yuriy
27.08.2017
07:34:57
Ну дык оно и не должно спасать если нормально моделька оформлена...
* обычно у всех через жопу, по крайней мере у большинства, где-то по субъективным кофейно-гуще-гаданиям 73%.

Den
27.08.2017
07:36:02
а можно пример, так сказать, жопы?)
кстати, много лет лезут гонки insert-update (в другом месте) - исключения логируются, операции повторяются "сверху" - как бы и пофиг :) Будет 2.5, перепишу, может быть..


Yuriy
27.08.2017
07:38:31
Типичная Жопа, это :
• Незнание того что на свете уже давно есть 6 нормальных форм
• неумение и непонимание как работать с предствлениями как на них ложить правила и триггеры, как при это происходит блокировка... (UDF желательно оформлять на сишке, потому что кошерно, иногда с x86 intrinsic'ами)
• Желание слезть на Cassandra/MongoDB когда есть BRIN/GIN
• Незнание и неумение разделения табличных пространств для холодных / тёплых / гарячих хранилищ
• Незнание и неумение готовки CQRS-ES'a и использования встроенного PUB/SUB'a для обновления сторонних представлений
etc
Я уже повидал овер дохера контор и стартапов с фразой "Ой, да кому нужны эти нормальные формы", потом через полгода: "Ой, Бля! у нас база уже до петабайта скоро дорастёт, между нодами вакханалия непонятная происходит - давайте слезать на NoSQL", через две недели после запила Монги: "Ой, чего-то у нас ларджовых EC2 нод стало в 3 раза больше, наверное к дождю".

Google

Yuriy
27.08.2017
07:44:10
На практике таблички и индексы, накладные расходы на синхронизацию, бывает растут экспоненциальненько... со всеми последствиями, и большой Абзац происходит совсем уж незаметно.
Прикольно когда все работают с БД, но никто их не умеет проектировать - потом боль & страдания & увеличение бюджета в 2-3 раза...

Den
27.08.2017
07:47:33
Полностью согласен. Хотя, насчёт нормальных форм вот, знать их обязательно, а вот ли использовать всегда и везде - вопрос.
".. использования встроенного PUB/SUB'a для обновления сторонних представлений" - а это что имеется в виду?
я разве что с notify игрался

Ilya
27.08.2017
07:49:23

Yuriy
27.08.2017
07:50:12
Проектирование любой реляционной СУБД с использованием всех 6ти нормальных форм подразумевает отсутствие избыточности и оптимальную индексацию - нет проблем с производительностью, ростом базы и журнала транзакций.
> а вот ли использовать всегда и везде - вопрос
Если на практике не ковыряли 200+ Гб таблички и не делали Explain на 10ти секундных запросах поверх кривых ормов рельсов/hibernate etc ... то естественно будет непонятно.

Ilya
27.08.2017
07:50:21
Да, на добавление удаление поля с sql тебе придется прогнать 3 релиза
Ничего страшного я в этом не вижу

Darafei
27.08.2017
07:50:46

Den
27.08.2017
07:51:40
@verrens , https://www.postgresql.org/docs/9.6/static/plpgsql-control-structures.html
Example 41-2. Exceptions with UPDATE/INSERT
Кстати, вот если честно, не вижу, чем в моём случае plpgsql-ные statement-ы могут помочь. Логика будет той же, только менее эффективно - у меня всё внутри одного запроса, а тут, по идее, разделение на императивные, так сказать, команды, с подзапросами

Darafei
27.08.2017
07:52:27
твой декларативный запрос и так разбирается в императивный план


Yuriy
27.08.2017
07:55:30
".. использования встроенного PUB/SUB'a для обновления сторонних представлений" - а это что имеется в виду?
Если у нас есть CQRS-ES в рамках базы - отдельно используется ограниченное мат. представления для сериализации, т.е. все наши JOIN'ы и тяжёлые запросы с сериализацией в JSON, последующей индексацией уплывают в мат. представление. Ограниченное (Constrainted) означает что мы эти данные храним месяц с последнего логина пользователя, и удаляем опосля... таким образом само представление можно хранить в отдельном табличном пространстве (Table Space) где-то на SSD'шке ещё и в пережатом виде через ZSON, а остальное в 6ой нормальной форме - где-то на православных винтах.
Также отдельно формируется не материализованное представление с правилами (RULES) на Запись (INSERT/UPDATE), которое подёргивает PUB/SUB, чистит кэш.
Таким образом у нас в рамках CQRS мат представление является моделью чтения, а простое - моделью записи.
ES при этом выполняет задачи блокировки и подчистки многоуровневых кэшей, обновления представлений, допустим он может подёргивать SSR какого-то SPA на Node.js / ClojureScript etc.


Den
27.08.2017
07:55:35

Yuriy
27.08.2017
07:55:51

Den
27.08.2017
07:56:34
максимально близко, так сказать, к кормушке

Yuriy
27.08.2017
07:57:24
... весь декларативный код бэкендов можно запихнуть в базу в рамках мат. представлений, правда у нас слишком дофига хомячков.

Google

Den
27.08.2017
08:03:08
@YuriyYarosh так "PUB/SUB" - это таки notify/listen, или я чего-то ещё пока не знаю?

Yuriy
27.08.2017
08:03:47
Да, это notify/listen

Den
27.08.2017
08:04:18
ээх, если бы там payload типизированный был..

Yuriy
27.08.2017
08:04:23
Просто есть много синонимов этого понятния - EventSource, Pub/Sub, Observable ...

Den
27.08.2017
08:04:40
И notify на ro-реплики распространялись.. Ну да мечтать не вредно
Где ?
в notify, вестимо. Там payload :: Text
а хотелось бы какой-нибудь произвольный record передать

Yuriy
27.08.2017
08:07:53
Мы раньше JSONB в бинарном виде гоняли %)
С парой хаков...

Den
27.08.2017
08:08:04
короч, оно в postgres-е слишком низкоуровневое
ну можно и так, да

Yuriy
27.08.2017
08:08:22
Это по SQL стандарту там просто TEXT ...

Yuriy
27.08.2017
08:08:44
В самом стандарте pub/sub не особо то и типизирован.
Я у себя пока просто JSON гоняю ... не то что бы быстро, но пока не жалуюсь - хватает.

Den
27.08.2017
08:09:10
главное, чтоб в 8000 байт влезло (интересно, откуда у них эта фицра-то вылезла?

Yuriy
27.08.2017
08:09:29
Размер страницы для текста

Den
27.08.2017
08:10:13
аа, точно. Надо будет потратить-таки время и изучить потроха постгреса.

Yuriy
27.08.2017
08:10:37
Очень помогает... особенно если влазить в мат представления и полноценный CQRS-ES ...
Бэкендщикам жизнь очень упрощает.

Den
27.08.2017
08:12:05
меня, кстати, в последнее время больше всего парит гонка между базой и её ro-репликами. Вот, например, вешается backend на listen (понятно дело, на rw, т.к. notify на реплики не распространяются), получает уведомление - и сделать бы ему теперь select на ro, но нет, не дошли до туда ещё данные. Эээх...

Google

Den
27.08.2017
08:12:32
в итоге на ro- остаются разве что тяжёлые отчёты всякие

Yuriy
27.08.2017
08:13:01
> тяжёлые отчёты всякие
Нужно правильно ворочить представлениями что бы такого не было. Вообще идеально - все агрегированные плюшки переписывать на сишку...

Den
27.08.2017
08:14:45
или вот банальный пример - проверка авторизационной сессии. На каждом запросе backend-а, даже если он из ro- только читает, приходится делать по select-у к rw-, ибо гонка-с.

Fike
27.08.2017
08:15:24

Den
27.08.2017
08:15:54

Yuriy
27.08.2017
08:16:32

Den
27.08.2017
08:17:33

Ilya
27.08.2017
08:17:49

Admin
ERROR: S client not available

Yuriy
27.08.2017
08:18:05

Den
27.08.2017
08:18:18
в любом случае, время между репликацией отнюдь не нулевое и при этом не особо-то предсказуемое, и с этим нельзя не считаться.

Yuriy
27.08.2017
08:18:51
Для сессий есть мемкеш и редис
Это нынче считается довольно плохой практикой - есть Stateless сессии, есть JWT. Куда бы не пришёл запрос - он нормально обработается.

Fike
27.08.2017
08:18:57
> EventSource == pub/sub
ох, нет

Stas
27.08.2017
08:19:52

Yuriy
27.08.2017
08:20:05

Den
27.08.2017
08:20:20
Для сессий есть мемкеш и редис
В общем-то да, но в моём случае это непозволительная роскошь, ибо сессия пользовательская есть, так сказать, процесс внутри Постгреса, и она может измениться/закрыться в любой момент.

Yuriy
27.08.2017
08:20:34

Fike
27.08.2017
08:21:14
Потому что это перпендикулярные понятия?
ES существует без того, чтобы кто-нибудь публиковал, а кто-то подписывался, и наоборот.

Den
27.08.2017
08:21:59

Google

Yuriy
27.08.2017
08:22:13

Den
27.08.2017
08:23:25
стоп, EventSource - вы имеете в виду тот, что в http?

Yuriy
27.08.2017
08:23:38
Нет, тот что в CQRS-ES.

Den
27.08.2017
08:24:14
аа, понятно, пардон.

Fike
27.08.2017
08:24:29

Stas
27.08.2017
08:24:34

Yuriy
27.08.2017
08:25:16
well that's an argument
Реализация декларативных плюшек в рамках представлений СУБД чуток полностью ставит крест на существующей C#/Java ORM-вакханалии.

Fike
27.08.2017
08:25:43
well that's another argument

Stas
27.08.2017
08:25:47
Для асинхронной можно спросить lsn на мастере и дождаться его на реплике

Den
27.08.2017
08:26:26

Stas
27.08.2017
08:28:02
Угу

Den
27.08.2017
12:46:58
А вот задача: надо выполнить запрос только в том случае, если некий подзапрос не вернул ни одной строчки.
Пока в голову пришёл лишь такой хак: With q As (..) Select tbl.* From tbl Left Outer Join q On (True) Where (q.some_field is Null)
Можно как-нибудь покрасивше?

Alexander
27.08.2017
12:54:47
Where not exists не подойдёт?

Den
27.08.2017
13:01:13

Alexander
27.08.2017
13:01:57

Den
27.08.2017
13:02:07
надо чаще документацию перечитывать :)

??Suffer
27.08.2017
13:02:09

Айтуар
27.08.2017
13:04:32

??Suffer
27.08.2017
13:07:20
=# select count(id) from rambo_vehicle;
count
----------
38817536
(1 row)
=# select count(id) from forensics_forensic;
count
----------
51960595
(1 row)
https://dumpz.org/2698499/
Есть запрос сгенерированый через Django ORM