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

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

Falc

Новичок
Originally posted by Апельсин
> Мускул выдает записи отсортированые по id

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

Апельсин

Оранжевое создание
все равно индекс у тебя используется, потому и упорядочено. Если индекс использоваться не будет, то и упорядочения автоматического не будет.
 

Falc

Новичок
Originally posted by Апельсин
все равно индекс у тебя используется, потому и упорядочено. Если индекс использоваться не будет, то и упорядочения автоматического не будет.
Ну если Мускул выдает записи упорядоченые по используемому индексу, тогда ORDER BY действительно не нужен
 

ForJest

- свежая кровь
Предлагаю супер вариант.
Фаза 1 - подготовка
1. создаем таблицу
[sql]
CREATE TABLE rand4table1
(
num INT NOT NULL AUTO_INCREMENT,
id_table1 INT NOT NULL,
PRIMARY KEY(NUM)
);
[/sql]
2. делаем соответсвенно
[sql]
INSERT INTO rand4table1
SELECT 0, id FROM table1;
[/sql]

Фаза 2 выборка.

1.
[sql]
SELECT @Cnt:=COUNT(NUM) cnt FROM rand4table1;
SELECT @id:=id_table1 FROM rand4table1 WHERE num = @Cnt*rand() LIMIT 1;
SELECT * FROM table_1 WHERE id = @id;
[/sql]
ипользуем cnt вместо Max - так как нам все равно, а мускулу приятнее.
используем rand мускулевский - зачем не знаю, но типа так независимее

Если нет записи - делаем еще один select - просто запись за дыркой
[sql]
SELECT * FROM table_1 WHERE id > @id ORDER BY id LIMIT 1;
[/sql]
и увеличиваем счетчик непопаданий.

2. проверяем счетчик непопаданий. Если он вышел за пределы некоего эмпирического критерия выполняем фазу 1.

Система автономна и устойчива. Операции нересурсоемки.

Можно вариант апргрейднуть с целью уменьшения кол-ва запросов - например делать сразу
[sql]
SELECT * FROM table_1 WHERE id >= @id ORDER BY id LIMIT 1;
[/sql]
и проверять на совпадение @id и id полученного, для выяснения попадания в дырку - не знаю что будет лучше.
---------------
Просто как новационная идея :) принимаются ахи, охи и помидоры на кетчуп.
 

Фанат

oncle terrible
Команда форума
Идею forjest-a комментировать не буду - она кажется СЛИШКОМ громоздкой.
Лишняя таблица, выборка ид ИЗ ВСЕЙ таблицы - это не дело.

А вот по идее Андрея П тут сообразился изъян очень печальный.
where-то использовать в этом случае нельзя :-(
Вся рандомизация к черту, если выбирается изо всей таблицы только 5 115, 134668б и 2456712 id

поэтому придется признать, что для поставленной задачи - выборка из всей таблицы - этот метод подходит идеально, если нет больших дырок в id.
но если в запросе есть where, то он не годится совсем...

Если есть where, то получается два варианта
Для случаев, когда выборка получается небольшая, не больше нескольких сотен записей, то order by rand() вполне себе нормально отработает, вычислит ранд () (если я не ошибаюсь) только для найденных записей.

Если же и where есть, и находится записей много - то тогда или
лимит ранд,1
или придумывать собственные спец. способы...
 

Green Mother

Guest
Я тут поразмыслил на досуге, раз уж тему подняли...

Пусть:
$N - переменная, размер таблицы.
$M - необходимое кол-во случайных строк.
Nmax - константа, приблизительный максимальный планируемый размер таблицы в обозримом будущем.

Создаем таблицу:
[sql]CREATE TABLE t (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
txt TEXT,
rnd INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
KEY rndkey (rnd)
)[/sql]

При каждом INSERT'е пишем:
PHP:
$rnd = rand(1, Nmax); //случайное число
[sql]INSERT INTO t(txt, rnd) VALUES ('Text', $rnd)[/sql]

Тогда вычисляем:
PHP:
$d = round((Nmax / $N) * $M * 2); // размер диапазона для выборки
$max = rand($d, Nmax); // верхняя граница
$min = $max - $d + 1; // нижняя граница
[sql]SELECT * FROM t WHERE rnd BETWEEN $min AND $max ORDER BY RAND() LIMIT $M[/sql]

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

ЗЫ: Все рассуждения приведены для больших таблиц. Всякие глупости, типа $M > $N, не учтены.
 

mars37

Новичок
Я всегда вот так делал:
1. select count(*) from {TABLES} {WHERE};
2. В PHP-коде берём случайное число в диапазоне от 1 до полученного в предыдущем пункте
3. select * from {TABLES} {WHERE} limit {число из предыдущего пункта}
 
Сверху