1. SQL / Говнокод #18644

    −44

    1. 1
    SELECT * FROM goods ORDER BY rand() LIMIT 10;

    В одном крупном московском интернет-магазине встала задача на главной странице сайта выдавать 10 случайных товарок. Как это было сделано, смотрите выше.
    Сайт несколько прилёг.

    Запостил: Solo, 27 Августа 2015

    Комментарии (31) RSS

    • ORDER BY rand() лучше не использовать. Никогда. Совсем никогда. Он сначала сортирует всю таблицу (да, все 100500 записей), а только потом выбирает 10 штук.

      В вот пример костыля, решающего эту проблему: http://plutov.by/post/order_by_rand_performance
      Ответить
      • Отож! :-) Тут никакие индексы не помогут. В таблице было несколько тысяч записей.

        К тому же, незачем так напрягаться ради каждого посетителя сайта. Кэширование тоже весьма полезно.
        Ответить
      • Еще вроде бы есть способ получить случайные записи с помощью RAND(), модулы и WHERE:

        SELECT * FROM products WHERE ROUND(RAND() * 1000 % 4) = 0 LIMIT 10
        Ответить
    • Для десяти товаров можно сгенерировать 10 случайных чисел в коде.
      Ответить
      • Так идентификаторы товара не угадаешь. Но, примерно, да.
        Ответить
        • Они последовательные или нет? Если нет - быстрее получения списка id ты не выберешь.
          Ответить
          • Товары иногда удалялись, так что непоследовательные.
            Да, нужен список id'шников. Но не обязательно выгребать его из базы каждый раз.
            В итоге был написан скрипт, который делает для всех пользователей раз в 10 минут.
            Ответить
            • >Но не обязательно выгребать его из базы каждый раз.
              можно сгенерировать скриптом базы, суть не поменяется, не?
              Ответить
            • Можно генерировать не id, а смещения от начала таблицы, а выбирать десятью запросами с LIMIT i,1. Правда, лимит с офсетом обычно жутко медленный.
              Ответить
              • >Правда, лимит с офсетом обычно жутко медленный.
                Хаха. А почему не O(1)?
                Ответить
                • Дай угадаю, потому что жаваебы соснули?
                  Ответить
                  • нет,
                    потому что базе необходимо сначала построить резалтсет, с учетом всех этих group order и т.д., потом "промотать" записи, которые надо поскипать, и лишь затем клиенту отдавать те строки, которые он попросил
                    Ответить
                    • вот же вы прямолинейные, а (
                      Ответить
                    • Не, ну серьезно - неужели нельзя выбрать случайную запись за О(1) или хотя бы не за О(n)?
                      Ответить
                      • если случайная - это "похер какая" (в частности, верхняя), и ты миришься с тем, что последовательные селекты могут возвращать всегда одно и то же, то СУБД может и оптимизнуть произвольный запрос

                        а если ты требуешь от СУБД _конкретные_ записи (а передавая в селект рандом ты хочешь именно этого), то будь добр предложить ей средства по эффективному извлечению этих _конкретных_ записей

                        в частности, индексы, партишионинг, параллельное исполнение, "кеширование" на стороне БД - да мало ли способов
                        Ответить
                        • Вероятностно редкие селекты не того можно исключить проверками.
                          Ответить
                          • я не понял к чему ты это
                            а к своему посту мне нечего прибавить
                            Ответить
                            • >я не понял к чему ты это
                              Выбираем случайные строки, в коде отсеиваем дубликаты.
                              Ответить
                              • какой профит базе данных на один и тот же селект "дай мне верхнюю строчку вот такого запроса" выдавать каждый раз разное, о каких редких проверках ты говоришь

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

                                когда ты не управляешь выбором подмножества - то для тебя такой результат будет как раз случайный, т.к. непредсказуемый, просто при стабильной БД он будет всегда один и тот же, хоть ты 1000 запросов сделай подряд
                                Ответить
                                • Я нейбу какой базе профит, спроси у нее. Напомню что мы обсуждаем: http://govnokod.ru/18644#comment297098
                                  Ответить
                                • >> она будет менять результат, только когда размазывание исходных данных по физическим блокам поменялось в такой мере, что очередность обхода этих блоков стала другой (например, данных стало тупо больше, или в кеше другие блоки оказались внезапно)

                                  Рандом за О(овер_дохуя(n))
                                  Ответить
                      • Если таблица по большей части read-only - можно. Просто сделай в ней поле с непрерывной нумерацией да дёргай.
                        Ответить
                  • Как ты догадался? Ты запустил эклипс и тут же почувствовал вкус спермы на губах?
                    Ответить
    • where (Случайное число от 0 до Max-1)>id limit 1,1
      Ответить

    Добавить комментарий