<rmcreative>

RSS

Все заметки с тегом «rand»

Можно уточнить:

    (1)
  1. Оптимизация ORDER BY RAND()

    10 января 2011

    Задача «выбрать 10 случайных постов» часто решается так:

    SELECT *
    FROM post
    ORDER BY RAND()
    LIMIT 10;

    Для совсем небольших проектов это будет работать, но когда проект начнёт расти начнутся проблемы. И начнутся они уже с 1500 записей. На моей рабочей машине этот запрос выполняется где-то 400мс.

    EXPLAIN показывает нам Using temporary; Using filesort, что означает создание временной таблицы (а для большого количества записей она ещё и на диск пишется) и не использование индекса. Виновник, как вы уже догадались — ORDER BY RAND().

    Чтобы использовать индекс можно выбрать не все данные, а только id:

    SELECT id
    FROM post
    ORDER BY RAND()
    LIMIT 10

    Теперь имея 10 id получим посты:

    SELECT post.*
    FROM (
        SELECT id
        FROM post
        ORDER BY RAND()
        LIMIT 10
    )  
    AS ids JOIN post ON post.id = ids.id

    Получаем результат примерно за 10мс, что несомненно лучше. Но и этого может не хватить.

    В этом случае можно поступить следующим образом:

    • По крону получить 10—20 вариантов случайных записей.
    • Записать в отдельную таблицу, предварительно очистив её.

    Далее делаем rand(1, 20) на сервере и выполняем очень простой и быстрый запрос:

    SELECT *
    FROM random_post
    WHERE random_id = :random_id

    Если нужно ещё быстрее — делаем аналог на Redis или memcached.

    14 комментариев