Wpis z mikrobloga

#programowanie #webdev #mysql #php

jak pobrać losową krotkę z bazy? przeglądam tak sobie internet i mam wrażenie, że nie ma najlepszego rozwiązania... tabela będzie miała do 1000 rekordów ale myślę, że mimo wszystko order by rand() to zły pomysł

jak dotąd pobierałem wszystko do tablicy w php i sobie losowałem, ale od kiedy strona główna wykonuje mi się ponad sekundę zacząłem trochę myśleć nad optymalizacją tego i owego :E
  • 32
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

@DESZCZE:

The second rule of Optimization Club is, you do not Optimize without measuring.


Pewny jesteś, że to to spowalnia? 1k rekordów to na dobrą sprawę mało, wątpię, żeby to spowalniało. Sprawdź lepiej, ile się skrypt wykonuje, a ile się odbywa już w przeglądarce.
  • Odpowiedz
@DESZCZE: opcji jest mnóstwo. Dodaj te 1000 rekordów do cache i losuj rand z przedziału 0 do count(tablica). Możesz też pobrać selectem count(*) z bazy i dać LIMIT 1,rekordOdKtoregoZaczac (randomowy ofkoz)
  • Odpowiedz
@DESZCZE: rand() jest mało wydajne przy dużej ilości rekordów. 1000 rekordów to prawie tyle co nic, więc problem pewnie leży gdzieś indziej. Ewentualnie możesz spróbować pobrać wszystkie id do tablicy, cachować i z tej tablicy wybrać x losowych id. Przy dużej ilości rekordów jest to nieporównywalnie szybsze od mysql'owego rand()
  • Odpowiedz
@DESZCZE: Rand to zly pomysl, bo nei dosc ze mysql losuje to jeszcze musi wszystko posortowac. Jesli masz tam pola typu text to sortuje zapisujac na dysku. Limit tez ci niewiele pomoze bo limit filtruje rzeczy dopiero przed wyslaniem do klienta, czyli pelne sortowanie i tak sie odbywa.

Jesli masz id na tych rekordach i te numery sa po kolei bez dziur, to chyba bym losowal w php jeden numer
  • Odpowiedz
@DESZCZE: poniżej masz porównanie szybkości wyciągania losowego recordu z bazy różnymi metodami. Tak jak wspomniał @msq rand() przy dużych bazach to tragiczny pomysł.

Selecting random record from MySQL database table.
  • Odpowiedz
@DESZCZE: jednym z prostych sposobów jest dodanie do tabeli pola random o typie float i zapisywanie do niego losowej liczby z przedzialu 0-1. Następnie jak chcesz wybrać losowy rekord, to losujesz jakąś liczbę z tego przedziału i wybierasz rekord który jest > od wybranej liczby, jeśli nie znajdzie, to wybierasz rekord <
  • Odpowiedz
niezupełnie:


@ozzie: Co nie zmienia faktu ze musi pobrac wszystkie rekordy (jesli nie masz nic w WHERE) i z nich wybrac najmniejszy / najwiekszy (jesli LIMIT 1). Losujac jedna liczbew aplikacji (jesli to tylko mozliwe) i pobierajac rekord z klazula

WHERE ID =

i zakladajac ze uzywasz do tego indexu to bedzie najszybsze rozwiazanie.
  • Odpowiedz
@DESZCZE: A nie możesz najpierw zapytać o liczbę rekordów, w PHP policzyć sobie rand() i potem zapytać tylko o ten jeden rekord o wylosowanym offsecie?
  • Odpowiedz
@msq: przecież w WHERE masz np. random > wylosowana liczba, jeśli masz index na random, to zostanie użyty i nie będzie pobierania wszystkich rekordów (bo po co).
  • Odpowiedz
Jesli masz id na tych rekordach i te numery sa po kolei bez dziur, to chyba bym losowal w php jeden numer z tego zakresu i z bazy pobieral tylko jeden rekord.


@msq: właśnie chodzi o to że są dziury
  • Odpowiedz
Pewny jesteś, że to to spowalnia? 1k rekordów to na dobrą sprawę mało, wątpię, żeby to spowalniało. Sprawdź lepiej, ile się skrypt wykonuje, a ile się odbywa już w przeglądarce.


@ogur: tą sekundę pokazuje mi profiler w firefoksie (czas html), a cały skrypt jest napisany w kohana 3, która chyba nie ma normalnego profilera, ludzie radzą żeby skorzystać z tego https://github.com/biakaveron/debug-toolbar ale nie mogę znaleźć dokumentacji

już postanowiłem przepisać całą
  • Odpowiedz