ФорумСообществоПрофессиональная деятельностьВзаимопомощь → Случайные записи. Подкиньте идей.

Случайные записи. Подкиньте идей.

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:34

    Boe идеи или ссылки на описанные сценарии.

    Предположим есть таблица в MySQL, где описаны фотографии. Набор полей значения не имеет, кроме ключа:

    CREATE TABLE photos (
    id INT NOT NULL auto_increment,
    /* … */
    PRIMARY KEY (id)
    );


    Фото часто удаляются, так что id идут не сплошняком, а с дырами.
    Предположим фотографий много — десятки и сотни тысяч. Требуется случайным образом выбрать 10 или 100 из них.

    Как это сделать быстро?

    На самом деле конечно будут дополнительные фильтрующие условия, но давайте начнем с простого — надо выбрать любые N фото. Быстро. Каждый раз новые.
    ιιlllιlllι унц-унц
  • AlexB

    Сообщения: 4306 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:39, спустя 4 минуты 50 секунд

    ORDER BY RAND() LIMIT 0,N
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:41, спустя 1 минуту 53 секунды

    Я так понимаю оно создаст временную таблицу с количеством записей совпадающим с photos.
    Красиво, но медленно.
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:41, спустя 25 секунд

    правильныйзапрос для такихх целей = select * from photo where id in (select id from photo order by rand() limit 5)
    Сапожник без сапог
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:42, спустя 29 секунд

    artoodetoo, ты стал интересные вопросы задавать :) продолжай в том же духе)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:43, спустя 1 минуту 23 секунды

    а я разве раньше задавал вопросы?
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:44, спустя 18 секунд


    Я так понимаю оно создаст временную таблицу с количеством записей совпадающим с photos.
    Красиво, но медленно.
    правильно полагаешь + потом еще будет файлсорт, что на 100 000 таблице положит сервер при частом обращении
    Сапожник без сапог
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 9:44, спустя 29 секунд

    artoodetoo, может путаю чего, но этот вопрос интересный. как с просонья :)))

    все убег дальше спать)
    Сапожник без сапог
  • Timur

    Сообщения: 1068 Репутация: N Группа: Джедаи
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 10:09, спустя 9 минут 1 секунду

    спасибо, я это видел. исходная статья предполагает сплошной набор без дыр!
    в обсуждении предлагается разное, но эффективного решения не предложили, imho
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 12:57, спустя 2 часа 47 минут 27 секунд

    У меня самого только такие мысли: никогда не использовать реально "случайные" записи. Отбирать сначала какое-то подмножество и уже в нем выбирать 10 случайных. Например выбирать 10 из 200 самых свежих или 10 из 200 самых проплюсованных.

    На чистом SQL такое не тестировал, возможно сервер не сумеет сделать эффективную выборку для составного запроса с двумя лимитами. Если не получится влоб, можно скомбинировать SQL + PHP. Также понятно что можно кешировать промежуточное подмножество.

    Update: уже точно знаю, что в MySql5 не получится SELECT … WHERE id IN (SELECT id … ORDER BY … LIMIT …)
    This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
    Но это не беда :)
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 13:33, спустя 36 минут 33 секунды

    смотри

    select id from links order by rand() limit 10


    вот такая штука у меня выполняется 1.5 секунды на 3 млонной таблице.

    select * from links inner join (select id from links order by rand() limit 10) as c on c.id=links.id

    вот такая столько же :)

    идеи: сделать по другому.
    нечто вот такое

    select id from links where id>max(id)*rand() limit 1


    но этот именно вариант не пригоден ибо ошибку скл пишет) сейчас нет врмеени углубиться сори

    можно выбрать произвольное начало и из него произвольной длины(от 1000 до 10000) элементов и по этим элементам уже order by rand() если сделать на хранимой процедуре, думаю будет удобно юзать + достаточно быстро работать. ну и конечно если проект с нагрузкой ожидается лучше это дело кешировать на пару секунд хотя бы)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 14:03, спустя 29 минут 29 секунд

    значит join (select…limit…) допускается? эт хорошо!

    можно выбрать произвольное начало и из него произвольной длины(от 1000 до 10000) элементов

    где-то должен быть max(id) полюбому. то есть три запроса или тройной составной.
    - max(id) - чтобы отступить от конца назад на rand(N)
    - подмножество select id order by limit
    - результирующий select * order by rand limit

    спинным мозгом чую — в эту сторону надо рыть — про подмножества. спасибо!
    и вот еще наткнулся http://www.parser.ru/forum/?id=7480

    P.S. дуд, ты же 4 часа назад спать собирался?
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 17 марта 2009 г. 15:52, спустя 1 час 49 минут 2 секунды

    http://www.parser.ru/forum/?id=7480


    хуйня какая то как и весь этот парсер.


    P.S. дуд, ты же 4 часа назад спать собирался?
    ты думаешь дают много поспать?)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 31 марта 2009 г. 15:24, спустя 13 дней 22 часа 32 минуты

    http://phpclub.ru/talk/showthread.php?postid=835177#post835177

    $max = select id from table order by id desc limit 1;

    $rand = mt_rand(1, $max);

    select * from table
    where id >= $rand
    order by id limit 1;

    ( правда это запрос на одну случайную запись. интересно чем max(*) не понравился? неужели desc limit 1 быстрее? )

    http://jan.kneschke.de/projects/mysql/order-by-rand

    SELECT name
    FROM random AS r1 JOIN
    (SELECT (RAND() *
    (SELECT MAX(id)
    FROM random)) AS id)
    AS r2
    WHERE r1.id >= r2.id
    ORDER BY r1.id ASC
    LIMIT 1;


    Multiple Rows at once

    If you want to get more than one row returned, you can:
    execute the Query several times
    write a stored procedure which is executing the query and stores the result in a temp-table
    make a UNION
    ιιlllιlllι унц-унц

Пожалуйста, авторизуйтесь, чтобы написать комментарий!