Случайная строка из большой таблицы

  • Автор темы Green Mother
  • Дата начала

Green Mother

Guest
Случайная строка из большой таблицы

Давно вопрос мучает. Есть большая таблица, на много тысяч записей. Нужно получить одну случайную строку. Вероятность получить каждую строку должна быть равновероятной. ORDER BY RAND() будет сканировать всю таблицу, для каждой строки вызывать RAND(), потом ее сортировать, вопщем, очень долго. Есть ли быстрый способ?
 

Фанат

oncle terrible
Команда форума
есть.
в этом форуме не меньше полусотни раз приводился.
поиск не пробовали?
 

Green Mother

Guest
попробовал. просмотрел с десяток тем, ни в одной не нашел варианта, в котором бы майскуль не просматривал бы всю таблицу.
хотя вариант c вычислением count(*) и LIMIT $rand, 1 работает побыстрее.
 

Andrew_P

Guest
Я бы сделал так (если есть ключевое AUTO_INCREMENT поле):

1. Узнал количество записей в таблице:
"select count(*) from t1";

2. Нашел случайную строку:
$rand_key = "select max(f_key) from t1 where f_key <= ".rand(1, <count(*)>);

3. Получил результат:
"select f1, f2, ..., fn from t1 where f_key = ".$rand_key;
 

Фанат

oncle terrible
Команда форума
андрюшенька, а слабо было четырьмя запросами? А пятью?

Мамаша, а где вы тут видите просмотр всей таблицы?
понятие "индекс" вам знакомо?
 

Green Mother

Guest
Мне - да. А Вам слово EXPLAIN?
Если да, то попробуйте (в таблице около 200000 записей):
EXPLAIN SELECT * FROM table LIMIT 100000, 1
и ORDER BY {PRIMARY_KEY} погоды не делает.
Реально, чтобы получить случайную строку (строго заданную LIMITом), майскуль перебирает, в среднем, полтаблицы.

Иногда лучше жевать, чем говорить (с)
 

Andrew_P

Guest
Автор оригинала: Фанат
андрюшенька, а слабо было четырьмя запросами? А пятью?
Мои три запроса работаю гараздо быстрее, чем LIMIT! Для получение одной случайной строки - это оптимальный вариант. Кто предложит более изящьный способ решения?

Автор оригинала: Фанат
понятие "индекс" вам знакомо?
А Вам знакомо понятие "ключ"?

Так что решать Вам, что использовать...

P.S. Лучше 10 запросов которые работают по 5 сек, чем 1 на час... ;)
 

si

Administrator
идея нормальная, но думаю лучше так:
[sql]
select max(pk) from table;
[/sql]
потом сгенерить рандом число от 0 до $max_pk-1 на РНР. потом
[sql]
select * from table where pk>$rand limit 1;
[/sql]
будет 2 запроса и оба весьма быстрые.
 

Andrew_P

Guest
Да, не плохо ;)

[ЦВЕТОМ=blue]select count(*) from t1[/ЦВЕТОМ] - тут не подойдет, т.к. записей наверняка меньше чем MAX(pk)!
 

Фанат

oncle terrible
Команда форума
ну что ж, буду знать.
спасибо за идею и извините за недоверие.
 

Фанат

oncle terrible
Команда форума
в некоторых случаях (когда в id большие перебои), рандомизатор будет работать фиговенько - первый айдишник за дыркой будет выпадать чаще.
но поскольку обычно такое бывает редко, а скорость обычно важнее строгой рандомности, то способ удачный.
 

Falc

Новичок
Да и для большей ровноти случайного распределения надо добавить Order BY

[SQL]
SELECT *
FROM TABLE WHERE pk > $rand
ORDER BY pk
LIMIT 1
[/SQL]
 

Фанат

oncle terrible
Команда форума
сортировка тут как раз не при чем.
нет смысла сортировать одну строку
 

Falc

Новичок
Originally posted by Фанат
сортировка тут как раз не при чем.
нет смысла сортировать одну строку
Ты хочешь сказать что условию WHERE pk > $rand
Удовлетворяет только одна строчка??? :)
Тогда зачем лимит? :)
 

Фанат

oncle terrible
Команда форума
ну тогда как раз сортировка-то и дает ухудшение рандомизации.
сортируем по пк, попадаем в дыру, и получаем всегда первое после дыры значение.
компрене ву?
 

Falc

Новичок
Originally posted by Фанат
ну тогда как раз сортировка-то и дает ухудшение рандомизации.
сортируем по пк, попадаем в дыру, и получаем всегда первое после дыры значение.
компрене ву?
Это так, но иначе у нас строки в большим значением pk будут появляться гораздо чаще, а с pk скажем равным 1-му вообще врядли выберется
 

Falc

Новичок
Originally posted by Фанат
почему?
Допустим максимальное значение pk = 10000
Тогда $rand будет всегда меньше 10000
Следовательно запись с pk=10000 будет всегда удавлетворять нашему условию WHERE pk > $rand
В то время как запись с pk=1 может выбраться только при $rand = 0

Вот и подумай какая запись будет чаще выбираться...
 

Falc

Новичок
Хотя сейчас попробовал запустил запрос:
[sql]
SELECT *
FROM table
WHERE id > 23
[/sql]

Мускул выдает записи отсортированые по id
А если без условия WHERE id > 23 выдает записи в разнобой.
Так что может быть сортировка тут и не обязательно, но лишней точно не будет.
 

Апельсин

Оранжевое создание
> Мускул выдает записи отсортированые по id

у тебя в этой таблице только поле id? Или индекс создан по всем полям таблицы ;)
Если да, то так и должно быть, т.к он будет брать все данные из индексного файла, а там значения упорядочены.
 
Сверху