Sobes.tech
Middle+

Kaip optimizuoti operatorių ORDER BY RAND()?

sobes.tech AI

Atsakymas iš AI

ORDER BY RAND() optimizavimas yra sudėtingas, nes jis reikalauja visų duomenų pasirinkimo, kad būtų sugeneruotas atsitiktinis skaičius kiekvienai eilutei. Įprasti būdai:

  1. Atsitiktinio identifikatoriaus pasirinkimas:

    • Gauti eilučių skaičių lentelėje.
    • Sugeneruoti atsitiktinį skaičių nuo 0 iki N-1 (arba 1 iki N).
    • Pasirinkti eilutę su atitinkamu poslinkiu arba OFFSET.
    SELECT COUNT(*) FROM your_table;
    -- Tarkime, bendras eilučių skaičius = N
    
    SELECT * FROM your_table LIMIT 1 OFFSET floor(random() * N);
    

    Šis metodas tinka vienos arba kelių atsitiktinių eilučių pasirinkimui. Nefektyvus dideliam eilučių skaičiui.

  2. Atsitiktinio pasirinkimo pagal id diapazoną:

    • Rasti minimalų ir maksimalų id.
    • Sugeneruoti atsitiktinį skaičių šiame diapazone.
    • Pasirinkti eilutę su id >= atsitiktinis_sk naudodami LIMIT.
    SELECT MIN(id), MAX(id) FROM your_table;
    -- Tarkime, gauti min_id, max_id
    
    -- Programoje sugeneruojame atsitiktinį `id` diapazone [min_id, max_id]
    -- Pavyzdžiui: atsitiktinis_id = min_id + floor(random() * (max_id - min_id + 1))
    
    SELECT * FROM your_table WHERE id >= atsitiktinis_id LIMIT 1;
    

    Gali praleisti eilutes, jei yra tarpai id reikšmėse.

  3. Sukurti laikinas lentelę arba naudoti subužklausą su rūšiavimu pagal atsitiktinį skaičių:

    • Pasirinkti duomenų pogrupį arba tik id subužklausoje.
    • Taikyti ORDER BY RAND() šiai pogrupiai.
    SELECT *
    FROM your_table AS t1 JOIN (SELECT id FROM your_table ORDER BY RAND() LIMIT 100) AS t2
    ON t1.id = t2.id;
    

    Sumažina apkrovą, jei LIMIT taikomas subužklausoje.

  4. Naudoti papildomą lauką su atsitiktiniu skaičiumi:

    • Pridėti lauką į lentelę atsitiktinio skaičiaus saugojimui.
    • Periodiškai atnaujinti šį lauką visoms eilutėms.
    • Rūšiuoti pagal šį lauką.
    -- Pridėti lauką
    ALTER TABLE your_table ADD random_sort_key FLOAT;
    
    -- Periodiškai atnaujinti
    UPDATE your_table SET random_sort_key = RAND();
    
    -- Pasirinkti
    SELECT * FROM your_table ORDER BY random_sort_key LIMIT 10;
    

    Reikalauja pakeitimų schemoje ir foninio atnaujinimo procese.

  5. "Maišymo" algoritmas (Fisher-Yates) už duomenų bazės ribų:

    • Pasirinkti visus id (arba visus duomenis, jei jie maži).
    • Maišyti sąrašą programoje.
    • Pasirinkti pirmuosius N elementus.
    // Tarkime, kad ids yra []int
    // ids = ... // Gauti ids iš duomenų bazės
    
    rand.Shuffle(len(ids), func(i, j int) {
        ids[i], ids[j] = ids[j], ids[i]
    })
    
    // Dabar pirmieji N elementai ids yra atsitiktiniai
    // Juos galima naudoti pilnų eilučių pasirinkimui
    // SELECT * FROM your_table WHERE id IN (...)
    

    Tinka tik mažų eilučių skaičiaus lentelėms.

Pasirinkti geriausią metodą priklauso nuo lentelės dydžio, reikalaujamo atsitiktinių eilučių skaičiaus ir konkrečios duomenų bazės valdymo sistemos. Daugeliu atvejų, kai reikia pasirinkti nedidelį kiekį atsitiktinių eilučių iš didelės lentelės, kombinacija id gavimo su vėlesniu OFFSET arba WHERE id IN (...) bus efektyvesnė nei grynas ORDER BY RAND().