2010-03-08 4 views
6

Я хотел бы разбивать страницы на случайный список моделей ActiveRecord (строки из базы данных MySQL).Стабильный/повторяемый случайный сортировка (MySQL, Rails)

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

Предположим, что существует достаточно объектов (десятки тысяч), которые хранят случайно отсортированные значения идентификатора в сеансе или в файле cookie слишком велики, поэтому я должен временно сохранять его каким-либо другим способом (MySQL, файл и т. Д.).).

Первоначально я думал, что могу создать функцию на основе идентификатора сеанса и идентификатора страницы (возвращающего идентификаторы объектов для этой страницы), однако, поскольку значения идентификатора объекта в MySQL не являются последовательными (есть пробелы), это казалось разваливались, когда я толкал его. Приятно, что для этого не требуется минимальное хранилище, но недостатки в том, что он, вероятно, довольно сложный для реализации и, вероятно, интенсивный процессор.

Мое чувство, я должен создать таблицу пересечений, что-то вроде:

random_sorts(sort_id, created_at, user_id NULL if guest) 

random_sort_items(sort_id, item_id, position) 

А потом просто хранить «sort_id» в сессии. Затем я могу разбивать на страницы random_sorts WHERE sort_id = n ORDER BY position LIMIT ... как обычно.

Конечно, я должен был бы положить туда какого-нибудь жнеца, чтобы удалить их после некоторого периода бездействия (на основе random_sorts.created_at).

К сожалению, мне пришлось бы аннулировать сортировку по мере создания новых объектов (и/или удаления старых объектов, хотя удаление очень редко). А при увеличении нагрузки размер/производительность этой таблицы (даже правильно проиндексированной) падает.

Кажется, что это должна быть проблема, но я не могу найти никаких плагинов для рельсов, которые это делают ... Любые идеи? Благодаря!!

ответ

6

MySQL имеет функцию RAND вы можете использовать в вашем предложении ORDER, передавая семя привязанного к пользовательскому сеансу.

ORDER BY RAND (?)

Где? является начальным значением из сеанса. Это даст вам возможность повторного заказа по всем запросам.

+0

Да, это работает до тех пор, пока строки в таблице никогда не меняются (если новый добавлен, я понимаю, что весь набор может измениться). Кроме того, он вызывает сканирование таблицы каждый раз, что может быть большим ударом производительности ... –

+0

Ваш комментарий кажется действительным (хотя иногда вы * хотите * все, что нужно использовать, если базовая таблица добавляет что-то новое). К сожалению, я не могу придумать, как это сделать, чтобы избежать сканирования всей таблицы каждый раз, хотя, может быть, «порядок по идентификатору 10» может быть достаточно умным, чтобы выйти из раннего ...). Если вы не делаете «порядок», то добавление новой записи все равно может быть рандомизировано для вашего вывода, AFAIK, так что это может быть трудный вопрос, чтобы получить право ... – rogerdpack

+0

выглядит как заказ rand then limit "does «по крайней мере, полное сканирование таблицы (в mysql), хотя могут быть трюки, которые вы могли бы использовать, чтобы избежать этого, чтобы ускорить это для больших таблиц: http://stackoverflow.com/questions/211329/quick-selection-of-a- случайные строки из-а-большой стол-в-MySQL/211388 – rogerdpack

2

Я, вероятно, что-то отсутствует, но будет не что-то вроде этого

select ... order by sha1(concat($session_id,item_id)) limit m,n;

работы, чтобы дать вам случайный упорядоченная, повторяемый для каждого сеанса постраничного списка? Не очень приятно использовать индекс, но вы избегаете каких-либо таблиц/аннулирования pre-fill/tmp.

0

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

srand user_id 
items.sort_by{ rand } 
+0

Это будет использовать много рубиновой памяти для сортировки всего массива, не так ли? –

+0

Я немного за пределами моей глубины, когда дело доходит до внутренней части, но поскольку это просто сортировка указателей, что было бы более эффективным способом? Возможно, это обычай. метод с переданным случайным семенем? http://stackoverflow.com/questions/2039902/how-does-rubys-sort-by-rand-work – ghoppe

+0

Еще одна возможная проблема заключается в том, что srand разделяется по всему вашему рубиновому процессу (AFAICT), поэтому, если вы мульти -прочитанный, а не синхронизированный, может быть возможность для условий гонки.В 1.9.2 я полагаю, что есть новый класс Random, который вы могли бы использовать вместо этого (но да, вы бы загрузили весь набор в ОЗУ, чего вы, возможно, избежите, см. В статье Тоби Хеде для mysql). – rogerdpack

Смежные вопросы