У меня есть тип лотерейной системы со случайным выбором, который я пытаюсь оптимизировать.
У меня есть следующие ограничения:
- Мне нужно применить SELECT ... FOR UPDATE только к строкам, где deal_id является текущей сделкой моего приложения (т.е. я не применяю его ко ВСЕЙ таблице / ко ВСЕМ строкам таблицы, только к тем, где например deal_id = 3 например)
- Мне нужно выбрать только строки, где доступно = true
- Мне нужно вывести только 1 строку (когда игрок покупает билет, я должен проверить эти 1 миллион строк и СЛУЧАЙНО выбрать одну для него (только одно из множества решений Stackoverflow, таких как здесь или TABLESAMPLE не работают легко)
- Обычно у меня есть около 1 миллиона строк, которые соответствуют deal_id = 3 (3 в качестве примера) и available = true (из общего числа около 30 миллионов строк в любой момент времени)
- У меня очень много READS и WRITES => от 50 до 100+ одновременных чтений в таблице и, как следствие, примерно такое же количество записей (как однажды выбрано, available = true изменяется на false внутри SELECT..for UPDATE)
- У меня блокировка, пока выполняется выбор / обновление в строке. Теперь я использую SELECT..FOR UPDATE с pg_try_advisory_xact_lock (и когда postgresql 9.5 выйдет из бета-версии, я буду использовать SKIP LOCKED)
- Мне нужна невероятно быстрая скорость. я нацеливаю запрос на ‹5 мс
- Что касается идентификаторов, могут быть огромные промежутки между идентификаторами в таблице в целом, НО внутри `` билетов из конкретной сделки '' (см. запрос ниже) нет никакого разрыва между идентификаторами (даже самыми маленькими), что, как я полагаю, может иметь значение чтобы найти наиболее подходящий запрос.
Вот мой текущий запрос. Это ПРОИЗВОЛЬНЫЙ ВЫБОР, но теперь я хочу изменить его / воссоздать, чтобы иметь СЛУЧАЙНЫЙ ВЫБОР (но избегайте обычного предела random () 1, который должен проходить через все 1M строк и работает очень медленно, даже, возможно, избежать смещения (?), поскольку он заведомо медленный на больших наборах данных).
UPDATE tickets s
SET available = false
FROM (
SELECT id
FROM tickets
WHERE deal_id = #{@deal.id}
AND available
AND pg_try_advisory_xact_lock(id)
LIMIT 1
FOR UPDATE
) sub
WHERE s.id = sub.id
RETURNING s.name, s.id
как изменить этот запрос, чтобы перейти от произвольного выбора к СЛУЧАЙНОМУ выбору и с максимально быстрым запросом?
Я хотел бы, если возможно, ощутимые предложения запросов, которые я попробую в своем приложении.
SKIP LOCKED
в подзапрос? - person Mikko Rantalainen   schedule 20.05.2021