powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Получение случайной записи (записей) из таблицы
5 сообщений из 5, страница 1 из 1
Получение случайной записи (записей) из таблицы
    #33209419
DocAl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вот не подскажет ли кто-нибудь оптимальный способ решения этой задачи?
Вот допустим, есть таблица table, из неё нужно получить случайную запись (кортеж), или несколько записей.
Решение в лоб:
Код: plaintext
1.
SELECT * FROM table ORDER BY rand() LIMIT $n;
имеет очевидные проблемы: все записи копируются во временную таблицу, после чего проводится сортировка в лоб, без индекса, и лишь затем из таблицы выбирается n записей. Т.е. если нужно извлечь одну случайную запись из большой таблицы, эта простая, вроде бы, операция, занимает значительное время и съедает немало ресурсов.
Для извлечения одной случайной записи можно сделать то же самое в два быстрых запроса:
Код: plaintext
1.
SELECT count(*) FROM table;
генерация случайного числа в диапазоне от 0 до count-1 на стороне клиента и
Код: plaintext
1.
SELECT * FROM table LIMIT $n,  1 
Метод, конечно, не идеальный, но для такой задачи более-менее адекватен, один запрос -- не догма.
Однако же, если нужно получить не одну случайную запись, а 10, 100, 1000?
1001 запрос или запрос с 999 юнионами мне уже кажется приемлемым.
Может быть, есть более приемлемое решение в рамках стабильной ветки MySQL?
...
Рейтинг: 0 / 0
Получение случайной записи (записей) из таблицы
    #33211623
Astron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
О! Интересный вопрос, наконец-то :-)
Я думаю так - если надо настоящую случайность, то это подразумевает затраты на перенумерацию всего набора, просто по-определению случайного процесса. Как оптимизировать перенумерацию - зависит от конкретного случая. Сервер копирует во временные таблицы, можно разве что "возглавить" этот процесс, создав такую таблицу самому, примерно так:
Код: plaintext
1.
2.
3.
4.
5.
select count(*) into @count_var from tbl1;
create table sort_tbl (index rand_ind (rnd)) 
          engine=memory 
           as 
             (select id, round(rand()*@count_var) as rnd from tbl1);
после чего получать что-то там может оказаться быстрее. Не уверен, не проверял :-)
Однако истинного выигрыша без поступления принципом случайности не получить никак, это математика.

Если, к примеру, брать каждую n-ю запись. N менять. Тогда просто 1 раз скан по таблице.

Или, неплохой вариант, сначала узнаем @count_var, потом выполняем что-то навроде
Код: plaintext
1.
select * from tbl1 where round(rand()*@count_var/  10  )= 1 ;
При этом мы получаем "примерно" 10 записей, что может удовлетворить условию задачи. Тем более что максимум можно ограничить LIMIT.

Либо хранить якобы "случайное" поле в БД. Как его заполнять, вопрос второй, решение зависит от задачи. Тут вообще производительность максимальная, так как для сервера данные упорядочены.
...
Рейтинг: 0 / 0
Получение случайной записи (записей) из таблицы
    #33212673
DocAl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо, интересный вариант.
Однако же, утверждение насчёт по определению невозможности получить этот случайный набор без явной перенумерации всех элементов -- я бы поспорил.
Ну, по крайней мере, если нас устраивает та степень "случайности", которую нам обеспечивает функция rand() и её аналоги. Ведь мне необязательно "нумеровать" случайными числами реальный ряд данных, он уже как-то пронумерован, при указании сортировки по, скажем, первичному ключу -- однозначно, т.е. в помощью ORDER BY id LIMIT n мы в любой момент времени имеем взаимно однозначное сопоставление произвольной записи какому-то определённому натуральному числу из отрезка [0; m], где m -- количество записей. Т.е. по-сути мы можем просто сгенерировать нужное количество случайных чисел, лежащих в диапазоне от 0 до m и с помощью LIMIT извлечь эти, в достаточной, для большинства случаев, степени, случайные записи. Проблема лишь в том, что если извлечь надо n чисел, это создаёт n+1, пусть и быстрых, запросов. Ну и по-хорошему, на время генерации случайных чисел и извлечения записей таблицу нужно либо блокировать, либо осуществлять всё это внутри транзакции. Ну транзакции-то в MySQL давно есть, это не проблема, а вот n+1 запросов выглядят некрасиво. Теоретически можно было бы поддерживать в таблице некоторый недырявый индекс cid0, начинающийся с нуля, и запрос делать с условием WHERE cid0 IN (a, b, c...), где a, b, c... -- те самые n случайных, по неявному условию задачи, различных целых числа из диапазона [0; m]. Проблема только в том, что поддерживать такой индекс в таблице с частыми удалениями записей будет довольно-таки накладно.)
В общем, вопрос в том, как бы скормить LIMIT не один аргумент, а список, грубо говоря)
...
Рейтинг: 0 / 0
Получение случайной записи (записей) из таблицы
    #33213436
Astron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну насчет поспорить - я бы послушал, у меня по этому предмету был твердый трояк. И было это лет 15 назад. Но смутно припоминается, что случайный процесс - это такой процесс, значение которого мы не можем предсказать в произвольный момент времени и зная начальную точку. А это есть перенумерация. Оставим пока в стороне алгоритм RAND, наверняка обычное само-отображение, нас тут может интересовать разве что равномерность распределения результатов. Итого, если уж угодно истинную (с поправкой на неидеальность RAND) случайность - перенумеровывай набор каждый раз, иначе ты "сможешь предсказать значение" процесса.... Просто случайные результаты бывают двух назначений - точный (казино, кидаем карты) и не особо точный (список кандидатов на сайте знакомств). Для первого варианта - перенумерация однозначно, для второго мой вариант со случайным (но довольно хорошо попадающим в нормальное распределение) количеством записей идеально подходит. Прикинь, сидит мужик, жизнь не удалась, все бросили, дай думает познакомлюсь - покажи мне сервер 10 случайных женщин - а ему в ответ 0! И это правильно будет :-) А кому-то выскочит 20 :-)
...
Рейтинг: 0 / 0
Получение случайной записи (записей) из таблицы
    #33213450
DocAl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я писал про перенумерацию... Попробую покороче)
При наличии взаимно однозначного отображения записей в базе, и некоторого отрезка натуральных чисел, нам необязательно "нумеровать" записи, можно и этот самый отрезок. Если это отрезок от 0 до m, и нужно получить n случайных записей -- то "нумерация" заключается в получении n различных случайных чисел из этого диапазона.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Получение случайной записи (записей) из таблицы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]