Sobes.tech
Middle+

Как да оптимизираме оператора ORDER BY RAND()?

sobes.tech AI

Отговор от AI

Оптимизирането на ORDER BY RAND() е трудно, тъй като изисква пълно извличане на данни за генериране на случайно число за всеки ред. Типичните подходи:

  1. Избор на случайно идентификатор:

    • Получаване на броя на редовете в таблицата.
    • Генериране на случайно число от 0 до N-1 (или 1 до N).
    • Избиране на ред с подходящо изместване или OFFSET.
    SELECT COUNT(*) FROM your_table;
    -- Предполага се, че общият брой редове = N
    
    SELECT * FROM your_table LIMIT 1 OFFSET floor(random() * N);
    

    Този метод е подходящ за избор на един или малък брой случайни редове. Не е ефективен за голям брой редове.

  2. Случаен избор по диапазон id:

    • Намерете минималния и максималния id.
    • Генерирайте случайно число в този диапазон.
    • Изберете ред с id >= случайното_число чрез LIMIT.
    SELECT MIN(id), MAX(id) FROM your_table;
    -- Предполага се, че са получени min_id, max_id
    
    -- В приложението генерираме случайно id в диапазона [min_id, max_id]
    -- Например: случайно_id = min_id + floor(random() * (max_id - min_id + 1))
    
    SELECT * FROM your_table WHERE id >= случайното_id LIMIT 1;
    

    Може да пропусне редове, ако има празни места в id.

  3. Създаване на временна таблица или използване на подзаявка с сортиране по случайно число:

    • Избиране на подмножество данни или само id в подзаявка.
    • Прилагане на ORDER BY RAND() към това подмножество.
    SELECT *
    FROM your_table AS t1 JOIN (SELECT id FROM your_table ORDER BY RAND() LIMIT 100) AS t2
    ON t1.id = t2.id;
    

    Намалява натоварването, ако LIMIT е наложен върху подзаявката.

  4. Използване на допълнително поле с случайно число:

    • Добавяне на поле към таблицата за съхранение на случайно число.
    • Периодично обновяване на това поле за всички редове.
    • Подреждане по това поле.
    -- Добавяне на поле
    ALTER TABLE your_table ADD random_sort_key FLOAT;
    
    -- Периодично обновяване
    UPDATE your_table SET random_sort_key = RAND();
    
    -- Избиране
    SELECT * FROM your_table ORDER BY random_sort_key LIMIT 10;
    

    Изисква промени в схемата и фоновия процес на обновяване.

  5. Алгоритъм "разбъркване" (Fisher-Yates) извън базата данни:

    • Избиране на всички id (или всички данни, ако са малки).
    • Разбъркване на списъка в приложението.
    • Избиране на първите N елемента.
    // Предполага се, че ids е []int
    // ids = ... // Получаване на ids от базата данни
    
    rand.Shuffle(len(ids), func(i, j int) {
        ids[i], ids[j] = ids[j], ids[i]
    })
    
    // Сега първите N елемента ids са случайни
    // Могат да се използват за избор на пълни редове
    // SELECT * FROM your_table WHERE id IN (...)
    

    Подходящо само за таблици с малък брой редове.

Изборът на най-добрия метод зависи от размера на таблицата, изисквания брой случайни редове и конкретната СУБД. За повечето случаи, когато трябва да се изберат малък брой случайни редове от голяма таблица, комбинацията от получаване на id с последващ OFFSET или WHERE id IN (...) ще бъде по-ефективна, отколкото чистият ORDER BY RAND().