?

Log in

No account? Create an account

Previous Entry | Next Entry

Помощь зала...

Вот интересная задача:

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


Пути решения:
Первый вариант:
добавить к каждой записи уникальный номер, всюду плотный (т.е. без дырок) и генерить в скрипте 20 случайных чисел. Минусы такого подхода в том, что не получится использовать кеширование (без извратов) и к тому же генератор случайностей в PHP-не очень...

Второй вариант:
генерить очередь (т.е. последовательность ID) и выбирать их оттуда по мере необходимости. Здесь возникает вопрос её генерации и ситуации, когда она закончится.

Третив вариант: ...


Есть у кого-нибудь идеи?

Comments

( 10 comments — Leave a comment )
akuklev
Oct. 12th, 2012 01:02 pm (UTC)
Хм, вот если одну случайную запись, то можно было бы
SELECT * FROM table LIMIT FLOOR(RAND()*(SELECT COUNT(*) FROM table)),1";

В принципе можно просто 20 раз повторить. Ну естественно при этом только один раз count замерить.
loingrim
Oct. 12th, 2012 07:12 pm (UTC)
Limit(a,b) непременно отберёт a+b записей и потом первые a выкенет. к тому же 20 таких запросов на пользователя... мне представляется, что оно будет не эффективнее, чем SELECT * FROM table ORDER BY RAND() LIMIT 20.

Я вот ещё про MongoDB думаю, но там, по сути, то же самое будет
akuklev
Oct. 12th, 2012 07:15 pm (UTC)
> Limit(a,b) непременно отберёт a+b записей и потом первые a выкенет. к тому же 20 таких запросов на пользователя...

Это какая ДБ так тупо работает? MySQL точно нет. MyPHPadmin для пролистывания таблиц использует именно команду с LIMIT, и разницы в скорости показывания первой и 15000 страницы я не обнаруживал...
loingrim
Oct. 12th, 2012 07:18 pm (UTC)
MySQL... Я недавно сталкивался с таким поведением. При пролистывании таблицы этого не заметно, потому что он юзает индекс. А вот если там какое-нибудь WHERE то начинается интересное.
akuklev
Oct. 12th, 2012 07:23 pm (UTC)
Такое поведение случается только при фильтрации (т.е. когда есть WHERE), потому что нужно определить, откуда где начинается запись за номером а. Иначе это и не реализуешь, кроме как через LIMIT a, b (SELECT ... WHERE ...).

Однако у нас, кажется, стоит задача, не включаяющая фильтрацию. Если фильтрация требуется, следует сделать внутриMySQLный кеш — временную отфильтрованную таблицу, и из неё выбирать рандомные записи.
loingrim
Oct. 12th, 2012 07:48 pm (UTC)
Мда. Фильтрация оказывается существенной. А она нужна. Записи будут нескольких типов и нужно выбирать или один тип или все типы. Впрочем, составной индекс эту проблему должен решить.
prijutme4ty
Oct. 12th, 2012 05:24 pm (UTC)
А что ты называешь кешированием? Чтобы случайные данные доставались много раз одни и те же? или как-то ещё?

М.б. если ты хочешь одному пользователю показывать данные каждый раз одинаковые, скажем минуту подряд, завести таблицу случайных id-шников, которая а пользователю выдавать rand_id, который он таскает из запроса в запрос. Ну и делать очистку таблицы по timestamp иногда

таблица будет вида (rand_id, timestamp, ids="27,383,17777,10,...") и запрос условно такой:
SELECT * FROM table WHERE id IN (SELECT ids FROM randrecords WHERE rand_id=... AND timestamp >= TIME() - 60 )

Я, если честно плохо понимаю, как работает кэширование уровня БД, если оно вообще бывает. Но наверное так можно? Ну или метка может быть кэширована на уровне генерации ответа?
loingrim
Oct. 12th, 2012 07:16 pm (UTC)
Под кешированием я понимаю отдачу одной и той же страницы всем юзерам, которые пришли в данную секунду. Т.е. кеширование на уровне скрипта, а не на уровне базы.
lodin
Oct. 12th, 2012 08:47 pm (UTC)
А насколько жесткие требования к случайности?
loingrim
Oct. 13th, 2012 10:53 am (UTC)
Одному пользователю не должен выдаваться один и тот же набор данных в одинаковой последовательности.
( 10 comments — Leave a comment )