Я занимаюсь разработкой Spring Boot REST API в Котлине. Основной базой данных является Postgresql, и я использую Spring Data JPA для доступа к базе данных.
У меня есть таблица с именем «Пользователи», где у меня есть некоторые пользовательские данные. Одним из свойств пользователя является «пол». Может иметь одно из двух значений: MALE или FEMALE.
Мне бы хотелось, чтобы в моем приложении была функция для поиска случайного числа (скажем, например, 20) людей определенного пола, которых я раньше не видел. Я имею в виду - давайте предположим, что у меня есть таблица, где я храню идентификаторы пользователей, которых я уже видел.
Итак, теперь я хочу получить 20 случайных пользователей из таблицы «Пользователи», где пол - это MALE, а id - не В [список идентификаторов, которые я видел].
Случайность запроса изначально привела меня к созданию нативного запроса вида:
SELECT * FROM users WHERE gender = :gender ORDER BY random() LIMIT :number
Однако я понял, что это может быть очень неэффективно, поскольку часть order by random()
будет сортировать всю таблицу (или ~ половину таблицы, если я выберу один пол).
Итак, моя вторая идея - позаботиться о случайности в коде. Поэтому я решил сделать вызов db, чтобы подсчитать количество пользователей (чтобы получить самый высокий идентификатор), затем сгенерировать некоторые значения идентификаторов в диапазоне от 0 до самого высокого, отфильтровать те, которые я видел, и затем выбрать пользователей из БД по идентификаторам:
val numberOfUsersInDatabase = userRepository.count()
val idsOfUsersVotedForBefore = voteService.findIdsOfUsersVotedFor(requestingUser.id!!)
val excludedIds = idsOfUsersVotedForBefore.plus(requestingUser.id)
val idsToFetch = random.longs(2*amountOfIds, 1L, numberOfUsersInDatabase)
.boxed()
.filter { num -> !excludedIds.contains(num) }
.limit(amountOfIds)
.collect(toSet())
val randomUsers = userRepository.findUsersByIds(idsToFetch)
Но в этом случае у меня нет возможности узнать, какой пол у случайно выбранного пользователя, поэтому у меня нет возможности отфильтровать результаты по полу перед тем, как сделать вызов db.
Подскажите, пожалуйста, как лучше справиться с этим?