Модераторы: 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



sergejzrsmile
первый пост темы, второе предложение 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.1878 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


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

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