Sobes.tech
Middle+

Jak zoptymalizować operator ORDER BY RAND()?

sobes.tech AI

Odpowiedź od AI

Optymalizacja ORDER BY RAND() jest trudna, ponieważ wymaga pełnego pobrania danych do wygenerowania losowej liczby dla każdego wiersza. Typowe podejścia:

  1. Wybór losowego identyfikatora:

    • Uzyskaj liczbę wierszy w tabeli.
    • Wygeneruj losową liczbę od 0 do N-1 (lub 1 do N).
    • Wybierz wiersz z odpowiednim przesunięciem lub OFFSET.
    SELECT COUNT(*) FROM your_table;
    -- Zakłada się, że łączna liczba wierszy = N
    
    SELECT * FROM your_table LIMIT 1 OFFSET floor(random() * N);
    

    Ta metoda nadaje się do wyboru jednego lub kilku losowych wierszy. Nieefektywna dla dużej liczby wierszy.

  2. Losowy wybór w zakresie id:

    • Znajdź minimalny i maksymalny id.
    • Wygeneruj losową liczbę w tym zakresie.
    • Wybierz wiersz z id >= losowa_liczba, używając LIMIT.
    SELECT MIN(id), MAX(id) FROM your_table;
    -- Zakłada się, że uzyskano min_id, max_id
    
    -- W aplikacji wygeneruj losowe id w zakresie [min_id, max_id]
    -- Na przykład: losowe_id = min_id + floor(random() * (max_id - min_id + 1))
    
    SELECT * FROM your_table WHERE id >= losowe_id LIMIT 1;
    

    Może pominąć wiersze, jeśli występują luki w id.

  3. Tworzenie tymczasowej tabeli lub użycie podzapytania z sortowaniem po losowej liczbie:

    • Wybierz podzbiór danych lub tylko id w podzapytaniu.
    • Zastosuj ORDER BY RAND() do tego podzbioru.
    SELECT *
    FROM your_table AS t1 JOIN (SELECT id FROM your_table ORDER BY RAND() LIMIT 100) AS t2
    ON t1.id = t2.id;
    

    Zmniejsza obciążenie, jeśli LIMIT jest nałożony na podzapytanie.

  4. Użycie dodatkowego pola z losową liczbą:

    • Dodaj do tabeli pole do przechowywania losowej liczby.
    • Okresowo aktualizuj to pole dla wszystkich wierszy.
    • Sortuj po tym polu.
    -- Dodanie pola
    ALTER TABLE your_table ADD random_sort_key FLOAT;
    
    -- Okresowa aktualizacja
    UPDATE your_table SET random_sort_key = RAND();
    
    -- Wybór
    SELECT * FROM your_table ORDER BY random_sort_key LIMIT 10;
    

    Wymaga zmian w schemacie i procesu aktualizacji w tle.

  5. Algorytm "tasowania" (Fisher-Yates) poza bazą danych:

    • Wybierz wszystkie id (lub wszystkie dane, jeśli są małe).
    • Tasuj listę w aplikacji.
    • Wybierz pierwsze N elementów.
    // Zakłada się, że ids to []int
    // ids = ... // Pobierz ids z bazy danych
    
    rand.Shuffle(len(ids), func(i, j int) {
        ids[i], ids[j] = ids[j], ids[i]
    })
    
    // Teraz pierwsze N elementów ids jest losowe
    // Możesz użyć ich do wyboru pełnych wierszy
    // SELECT * FROM your_table WHERE id IN (...)
    

    Nadaje się tylko dla tabel z niewielką liczbą wierszy.

Wybór optymalnej metody zależy od rozmiaru tabeli, wymaganego liczby losowych wierszy i konkretnego systemu zarządzania bazą danych. W większości przypadków, gdy trzeba wybrać niewielką liczbę losowych wierszy z dużej tabeli, bardziej wydajne będzie pobranie id i następnie użycie OFFSET lub WHERE id IN (...), niż bezpośrednie sortowanie po RAND().