| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > MySQL > Выборка случайной записи из большой таблицы |
| Автор: dm9 2.11.2006, 12:09 | ||
| Здравствуйте. У меня стоит задача (быстрой) выборки одной случайной строки из таблицы. MySQL 4.1/5. Я вижу несколько вариантов. 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. Есть ли ещё какие-то варианты для реализации подобных выборок? |
| Автор: skyboy 2.11.2006, 12:31 |
| 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) |
| Автор: dm9 2.11.2006, 18:04 |
| Интересное решение. Спасибо. А ещё у кого-нибудь варианты есть под MySQL? |
| Автор: sergejzr 18.4.2007, 16:20 |
| Меня тоже вопросик интересует... |
| Автор: Gold Dragon 18.4.2007, 20:59 |
| а можно ли в MySQL вытащить из таблицы определённую записть по номеру, ну типа как в ассоциативном массиве вытащить запись по порядку? Можно было бы сгенерить просто случайное число и вытащить запись с этим номером ... |
| Автор: Gold Dragon 19.4.2007, 06:38 | ||
| согласен. кстати
|
| Автор: dm9 19.4.2007, 12:41 |
| Помнится, мы экспериментировали, и работало это очень долго на больших таблицах. Видимо, MySQL считает этот RAND() для каждой записи таблицы, а потом filesort... Теоретически "ORDER BY RAND()" можно было бы попробовать соптимизировать внутри СУБД, но, видно, этого по каким-то причинам не сделали. Кстати, по-моему, даже в официальном мануале было что-то сказано по поводу того, что для больших таблиц ORDER BY RAND() делать не рекомендуется. Это можно найти в описании ф-ции RAND(), если интересно. |
| Автор: kronos_vano 9.3.2009, 10:27 | ||
Мой вариант |
| Автор: Бонифаций 9.3.2009, 12:13 | ||||
пойдем заново по кругу? А если id в таблице с пропусками? скажем id с 1000 до 2000 отсутствует? тогда по Вашей схеме id 2000 будет выбираться чаще других.. |
| Автор: sergejzr 9.3.2009, 16:27 |
| Кстати вроде не было метода: 1) cnt="select count(*) from t where bla bla" Этот запрос закешируется, а если условия нет, то count(primary_key) вообще всегда готовый лежит. т.е высчитывать не надо каждый раз. Ну а дальше высчитываем случайное число r=rand(cnt): И наконец: "select * from <table> where bla bla limit r,1;" |
| Автор: skyboy 9.3.2009, 16:47 |
| sergejzr, первый пост темы, второе предложение dm9 но, пожалуй, самый правильный способ, потому не лишне будет ещё раз про него упомянуть. |
| Автор: sergejzr 9.3.2009, 18:01 |
| Да, что-то я бояню |
| Автор: kronos_vano 9.3.2009, 21:16 |
| Бонифаций, есть предложения как сделать лучше для таблицы с миллионами записей? |
| Автор: Бонифаций 10.3.2009, 03:59 | ||
правильный путь озвучен здесь http://jan.kneschke.de/projects/mysql/order-by-rand/ |
| Автор: sergejzr 10.3.2009, 11:14 |
| В принципе триггером содержать таблицу идентификаторов не такая уж плохая идея. |
| Автор: sergejzr 14.8.2009, 12:23 | ||
| ещё один способ: Предположим надо выбрать из таблицы "cooccurrences" 2 случайных записей. $cnt нам известен,. Скриптом генерим два случайных числа rand()%$cnt. предположим получились 15,20
Получается, что запрос нумерует все записи таблицы и выбирает номера, которые нам нужны. Во многих случаях это должно работать весьма быстро. |