Выберите N случайных записей в SQL Server без повторений - PullRequest
1 голос
/ 24 апреля 2011

Как выбрать N случайных записей из таблицы за раз без повторения записей, ранее возвращенных одной и той же операцией?

Очевидное решение:

SELECT TOP 5 * FROM
MyTable
WHERE Id NOT IN (SELECT Id FROM PreviouslyReturned)
ORDER BY newid()

Но разве это не будет действительно неэффективно, когда MyTable начнет расти?

У меня длинный список записей, и мне нужно по пять записей за раз для пошаговой игры без повторения каких-либо записей, уже собранных для данной игры. Поскольку я знаю приблизительно, сколько ходов произойдет, я мог бы выбрать случайную выборку до начала игры, которая будет довольно большой, но я бы предпочел, чтобы она была «динамичной». Я нашел этот вопрос , который использует случайное начальное число с MySQL.

Со временем будет так много записей, что повторение не будет проблемой (записи >> N), но до тех пор мне нужно, чтобы записи были уникальными. В качестве идентификатора я использую Fluent NHibernate для своего слоя постоянства; возможно, в NHibernate есть какая-то особенность, которая позволяет это.

Ответы [ 3 ]

2 голосов
/ 25 апреля 2011

без повторения каких-либо записей

Это не называется выбор случайных записей среди программистов. Выбранные значения случайным образом повторяются чаще, чем вы думаете, и фактически подсчет количества и длины повторений является одним из способов, с помощью которых статистики обнаруживают мошенничество.

То, что вы ищете, называется shuffle . Перемешивание рандомизирует порядок конечного набора вещей, таких как карты или ключи. (Рандомизация порядка строк не означает то же самое, что выбор случайных строк.)

В вашем случае планируйте хранить набор ключей, уже использованных для каждого пользователя. Выберите случайный набор строк, которых еще нет в этом наборе. Есть несколько способов хранения каждого случайного набора строк (ключей); убедитесь, что вы можете сказать, какой из них последний или текущий набор.

0 голосов
/ 28 апреля 2011

Вы можете просто сохранить все первичные ключи вашей таблицы во второй таблице, выбрать случайным образом из этой (извлечь связанные строки из исходной таблицы) и удалить их после выбора (конечно, из вспомогательной таблицы).

Я ожидал бы, что этот способ будет более эффективным, чем сохранение уже использованных ключей и создание предложения WHERE NOR IN (соответственно EXCEPT) (удаление должно быть примерно таким же эффективным, как и вставка, а выбор должен работать значительнобыстрее без дополнительной оговорки).Но, конечно, это должно быть доказано (с помощью профилирования ...)

Выбор пяти случайных идентификаторов должен работать нормально, используя подход из вопроса , который вы цитировали.

0 голосов
/ 25 апреля 2011

Попробуйте

SELECT TOP 5 *
FROM YOUR_TABLE
ORDER BY CHECKSUM(NEWID())

Здесь есть связанный вопрос, который детально описывает семантику случайного выбора в случайном порядке: Случайный выбор не всегда возвращает одну строку

SQL Server оценивает RAND один раз для каждого запроса, что означает, что трюк mySQL не будет работать в любом случае.

Редактировать: этого также достаточно

SELECT TOP 5 *
FROM YOUR_TABLE
ORDER BY NEWID()

Я прочитал ваш обновленный вопрос и у меня есть другое предложение:
Создание индексированного представления для

SELECT mt.*
FROM MyTable mt
LEFT JOIN PreviouslyReturned pr ON mt.Id = pr.Id
WHERE pr.Id Is NULL

или чего-то подобного

Тогда

SELECT TOP 5 *
FROM YOUR_INDEXED_VIEW
ORDER BY NEWID()
...