Я представляю таблицу с, скажем, миллионами записей.Вы хотите выбрать строку случайным образом, поэтому вы генерируете одно случайное число на строку, т.е. миллион случайных чисел, а затем ищите строку с минимальным сгенерированным числом.Здесь выполняются две задачи:
- генерация всех этих чисел
- нахождение минимального числа
и последующий доступ к записи курса.
Если вам нужно более одной строки, СУБД может отсортировать все записи и затем вернуть n записей, но, надеюсь, она предпочла бы применить некоторую операцию частичной сортировки, когда она обнаруживает только n минимальных чисел.Во всяком случае, какое-то задание.
Полного пути, как мне кажется, не существует.Если вам нужен произвольный доступ, то это путь.
Если бы вы были готовы жить с менее случайным результатом, я бы посоветовал сделать корзины с идентификаторами.Представьте, что ID сегментов 000000-0999999, 100000-1999999, ... Затем случайным образом выберите один сегмент, и из этого выберите случайные строки.Ну, по общему признанию, это не выглядит очень случайным, и вы получите либо старые, либо только новые записи с такими группами;но он иллюстрирует технику.
Вместо создания сегментов по значению, вы создадите их с помощью функции по модулю.id % 1000
даст вам 1000 ведер.Первый с идентификаторами xxx000, второй с идентификаторами xxx001.Это позволит решить проблему с новыми / старыми записями и сбалансировать ведра.Поскольку идентификаторы - это просто техническая вещь, совершенно неважно, что нарисованные идентификаторы выглядят очень похожими.И даже если это вас беспокоит, тогда не делайте 1000 бакетов, а говорите 997.
Теперь создайте вычисляемый столбец:
alter table mytable add column bucket int generated always as (id % 997) stored;
Добавьте индекс:
create index idx on mytable(bucket);
И запрос данных:
select *
from mytable
where bucket = floor(rand() * 998)
order by rand()
limit 10;
Только около 0,1% таблицы попадает в сортировку здесь.Так что это должно быть довольно быстро.Но я предполагаю, что платит только с очень большой таблицей и большим количеством сегментов.
Недостатки метода:
- Может случиться, что вы не получите столько строккак вы хотите, и вам придется запросить снова.
- Вы должны выбрать номер по модулю с умом.Если в таблице всего две тысячи записей, вы, конечно, не сделаете 1000 сегментов, но, возможно, 100 и никогда не будете требовать больше, скажем, десяти строк за раз.
- Если таблица увеличивается и растетодноразово выбранное число больше не может быть оптимальным, и вы, возможно, захотите изменить его.
Ссылка на реекстер: http://rextester.com/VDPIU7354
ОБНОВЛЕНИЕ: Это только что осенилона мне, что сегменты будут действительно случайными, если сгенерированный столбец будет основан не на модуле по идентификатору, а на RAND
значении:
alter table mytable add column bucket int generated always as (floor(rand() * 1000)) stored;
, но MySQL выдает ошибку "Выражениесгенерированного столбца 'bucket' содержит запрещенную функцию ".Это, кажется, не имеет смысла, так как недетерминированная функция должна быть в порядке с опцией STORED
, но по крайней мере в версии 5.7.12 это не работает.Может быть, в более поздней версии?