Модераторы: skyboy

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Выборка случайной записи из большой таблицы 
:(
    Опции темы
dm9
Дата 2.11.2006, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дмитрий Копытин
****


Профиль
Группа: Vingrad developer
Сообщений: 3876
Регистрация: 22.7.2002
Где: Москва

Репутация: нет
Всего: 137



Здравствуйте.

У меня стоит задача (быстрой) выборки одной случайной строки из таблицы. MySQL 4.1/5.

Я вижу несколько вариантов.
1. Метод чисто СУБД-шный.
Код
SELECT ... ORDER BY RAND() LIMIT 1

Почему это не работает на большой таблице — понятно.

2. Использование скриптового кода.
$cnt = (SELECT COUNT(*) FROM ...)
$rnd = rand(0, $cnt-1)
Затем SELECT ... LIMIT $rnd, 1
Ну или то же самое запихать в хранимую процедуру в MySQL 5.

3. Оптимизированный второй вариант.
Периодически (кроном или т. п.) выполнем выборку $cnt = (SELECT COUNT(*) FROM ...)
Затем в своём скрипте считываем этот $cnt и используем далее как во втором варианте.
Только нужна проверка — если число выбранных таким образом строк равна нулю, значит, строки удалились — тогда делаем ещё раз COUNT(*) и далее опять как во втором варианте.
Если строки удаляются редко, этот вариант в большинстве случаев экономит нам один запрос, хотя иногда приводит к трём запросам вместо 1 или 2.

Есть ли ещё какие-то варианты для реализации подобных выборок?


Это сообщение отредактировал(а) dm9 - 2.11.2006, 12:10
PM MAIL ICQ   Вверх
skyboy
Дата 2.11.2006, 12:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 41
Всего: 260



dm9, если в этой таблице есть автоинкрементый ключ, то можно сгенерировать rand(max(id)-min(id))+min(id) и выбрать первое значение, большее этого... ORDER BY id должен ведь сработать...
что-то вроде
SELECT ... FROM <table> WHERE id> rand()*(max(id) - min(id))+min(id) ORDER BY id limit 1
Впрочем, order делать не надо, то, что вернет тебе в случайном порядке, даже лучше... впрочем, надо бі изучить распределение при помощи опытов...
т.е. результат:
SELECT ... FROM ... WHERE id> rand()*(max(id)-min(id)) + min(id)
PM MAIL   Вверх
dm9
Дата 2.11.2006, 18:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дмитрий Копытин
****


Профиль
Группа: Vingrad developer
Сообщений: 3876
Регистрация: 22.7.2002
Где: Москва

Репутация: нет
Всего: 137



Интересное решение. Спасибо.

А ещё у кого-нибудь варианты есть под MySQL?

PM MAIL ICQ   Вверх
sergejzr
Дата 18.4.2007, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 1
Всего: 360



Меня тоже вопросик интересует...


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
Gold Dragon
Дата 18.4.2007, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 2
Всего: 71



а можно ли в MySQL вытащить из таблицы определённую записть по номеру, ну типа как в ассоциативном массиве вытащить запись по порядку? 
Можно было бы сгенерить просто случайное число и вытащить запись с этим номером ...


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
sergejzr
Дата 18.4.2007, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 1
Всего: 360



Цитата(Gold Dragon @  18.4.2007,  19:59 Найти цитируемый пост)
Можно было бы сгенерить просто случайное число и вытащить запись с этим номером ...

Можно что-то вроде этого, но если эта запись не будет соответствовать другим условиям выборки?


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
Gold Dragon
Дата 19.4.2007, 06:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 2
Всего: 71



согласен. 

кстати
Цитата(dm9 @  2.11.2006,  12:09 Найти цитируемый пост)
1. Метод чисто СУБД-шный.код
SQL1:SELECT ... ORDER BY RAND() LIMIT 1
Почему это не работает на большой таблице — понятно.
И на сколько этоплохо



--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
dm9
Дата 19.4.2007, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дмитрий Копытин
****


Профиль
Группа: Vingrad developer
Сообщений: 3876
Регистрация: 22.7.2002
Где: Москва

Репутация: нет
Всего: 137



Помнится, мы экспериментировали, и работало это очень долго на больших таблицах.
Видимо, MySQL считает этот RAND() для каждой записи таблицы, а потом filesort... Теоретически "ORDER BY RAND()" можно было бы попробовать соптимизировать внутри СУБД, но, видно, этого по каким-то причинам не сделали.

Кстати, по-моему, даже в официальном мануале было что-то сказано по поводу того, что для больших таблиц ORDER BY RAND() делать не рекомендуется. Это можно найти в описании ф-ции RAND(), если интересно.

PM MAIL ICQ   Вверх
kronos_vano
Дата 9.3.2009, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 13.7.2007

Репутация: нет
Всего: нет



Код

select * from <table> where id>=(select FLOOR(RAND() * COUNT(*)) from <table>) limit 1;

Мой вариант smile
PM MAIL   Вверх
Бонифаций
Дата 9.3.2009, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 827
Регистрация: 15.9.2005
Где: Brisbane

Репутация: 20
Всего: 40



Цитата(kronos_vano @ 9.3.2009,  10:27)
Код

select * from <table> where id>=(select FLOOR(RAND() * COUNT(*)) from <table>) limit 1;

Мой вариант smile

пойдем заново по кругу? 

А если id в таблице с пропусками? скажем id с 1000 до 2000 отсутствует? тогда по Вашей схеме id 2000 будет выбираться чаще других.. 





--------------------
 Бонифаций.
 
PM MAIL ICQ Skype GTalk Jabber YIM   Вверх
sergejzr
Дата 9.3.2009, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 1
Всего: 360



Кстати вроде не было метода:

1) cnt="select count(*) from t where bla bla"

Этот запрос закешируется, а если условия нет, то count(primary_key) вообще всегда готовый лежит. т.е высчитывать не надо каждый раз.

Ну а дальше высчитываем случайное число r=rand(cnt):

И наконец:

"select * from <table> where bla bla limit r,1;"


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
skyboy
Дата 9.3.2009, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 41
Всего: 260



sergejzr, smile
первый пост темы, второе предложение dm9 smile
но, пожалуй, самый правильный способ, потому не лишне будет ещё раз про него упомянуть.
PM MAIL   Вверх
sergejzr
Дата 9.3.2009, 18:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 1
Всего: 360



Да, что-то я бояню smile


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
kronos_vano
Дата 9.3.2009, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 13.7.2007

Репутация: нет
Всего: нет



Бонифаций, есть предложения как сделать лучше для таблицы с миллионами записей?
PM MAIL   Вверх
Бонифаций
Дата 10.3.2009, 03:59 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 827
Регистрация: 15.9.2005
Где: Brisbane

Репутация: 20
Всего: 40



Цитата(kronos_vano @ 9.3.2009,  21:16)
Бонифаций, есть предложения как сделать лучше для таблицы с миллионами записей?

правильный путь озвучен здесь у Яна


--------------------
 Бонифаций.
 
PM MAIL ICQ Skype GTalk Jabber YIM   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0602 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.