Wybieranie losowych wierszy jest zawsze trudne i nie ma doskonałych rozwiązań, które nie wiążą się z pewnym kompromisem. Albo pogorszyć wydajność, albo pominąć nawet losową dystrybucję, albo pogorszyć szansę na wybór duplikatów itp.
Jak wspomina @JakeGould, każde rozwiązanie z ORDER BY RAND()
nie skaluje się dobrze. Wraz ze wzrostem liczby wierszy w tabeli, koszt sortowania całej tabeli w sortowaniu plików staje się coraz gorszy. Jake ma rację, że zapytanie nie może być buforowane, gdy porządek sortowania jest losowy. Ale nie obchodzi mnie to tak bardzo, ponieważ zwykle wyłączam pamięć podręczną zapytań (ma swoje własne problemy ze skalowalnością).
Oto rozwiązanie umożliwiające wstępne losowanie wierszy w tabeli poprzez utworzenie kolumny z numerem wiersza i przypisanie unikalnych kolejnych wartości:
ALTER TABLE products ADD COLUMN rownum INT UNSIGNED, ADD KEY (rownum);
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Teraz możesz uzyskać losowy wiersz przez wyszukiwanie indeksu, bez sortowanie:
SELECT * FROM products WHERE rownum = 1;
Lub możesz uzyskać następny losowy wiersz:
SELECT * FROM products WHERE rownum = 2;
Możesz też uzyskać 10 losowych wierszy na raz lub dowolną inną liczbę, bez duplikatów:
SELECT * FROM products WHERE rownum BETWEEN 11 and 20;
Możesz ponownie losować w dowolnym momencie:
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Sortowanie losowe nadal jest kosztowne, ale teraz nie musisz tego robić przy każdym zapytaniu SELECT. Możesz to zrobić zgodnie z harmonogramem, miejmy nadzieję, że poza godzinami szczytu.