Order by Rand() i Symfony2

random

Att hämta en slumpmässig rad från en MySQL är ganska enkelt. Man lägger till ORDER BY RAND() i slutet på sin query. Nackdelen är att det går extremt långsamt. Den har en tidskomplexitet på O(n*log(n)). Det är därför Doctrine har valt att inte implementera den funktionen. Men vad gör man då om man vill plocka ut en slumpmässig rad från en tabell?

Man ska göra slumpmässigheten i applikationen. En naiv lösning är att hämta alla rader och göra en array_rand() på resultatet. Detta är naturligtvis inte optimalt då det tar massa minne i onödan. En lösning som jag brukar använda mig av är denna:


public function findOneRandom(){
   $max=$this->getMaxId();
   return $this->getEntityManager()
     ->createQuery('SELECT e FROM MyappMyBundle:Entity e
        WHERE e.id >= :rand
        ORDER BY e.id ASC')
     ->setParameter('rand',rand(0,$max))
     ->setMaxResults(1)
     ->getSingleResult();
}

private function getMaxId(){
   return $this->getEntityManager()
      ->createQuery('SELECT MAX(e.id) FROM MyappMyBundle:Entity e')
      ->getSingleScalarResult();
}

Detta letar efter det största id som du har i din tabell. Sen slumpar den ett värde (rand) mellan 0 och det största id. Vi returnerar sedan en rad i tabellen som är närmast större eller lika med vårt slumpade värde.

Jag vill dock varna att denna funktion antar att det finns minst ett värde i tabellen. Om du är osäker på om din tabell är tom eller inte så bör du använda getResult() istället för getSingleResult().



Relaterat:

  1. Unikt index med Doctrine och Symfony2
Skrivet augusti 8th, 2012 av