Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Robisz chwilę / pętlę, aby uzyskać 10 losowych wyników

Proszę, przestań używać ORDER BY RAND() . Przestań. Ta operacja ma złożoność n*log2(n) , co oznacza, że ​​wydłużyłby się czas spędzony na zapytaniach "

    entries  |  time units
  -------------------------
         10  |         1     /* if this takes 0.001s */
      1'000  |       300
  1'000'000  |   600'000     /* then this will need 10 minutes */

Jeśli chcesz generować losowe wyniki, utwórz procedurę składowaną, która je generuje. Coś takiego (kod zaczerpnięty z tego artykułu , które warto przeczytać):

DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
  DROP TEMPORARY TABLE IF EXISTS rands;
  CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) );

loop_me: LOOP
    IF cnt < 1 THEN
      LEAVE loop_me;
    END IF;

    SET cnt = cnt - 1;

    INSERT INTO rands
       SELECT tags.tagname
         FROM tags 
         JOIN (SELECT (RAND()*(SELECT MAX(tags.id) FROM tags)) AS id) AS choices
        WHERE tags.id >= choices.id
        LIMIT 1;

  END LOOP loop_me;
END$$
DELIMITER ;

Aby z niego skorzystać, napisałbyś:

CALL get_rands(10);
SELECT * FROM rands;

Jeśli chodzi o wykonywanie tego wszystkiego po stronie PHP, powinieneś przestać używać starożytnego mysql_* API. Ma ponad 10 lat i nie jest już konserwowany. Społeczność nawet rozpoczęła proces za ich deprecjonowanie. Nie powinno być więcej nowego kodu napisanego za pomocą mysql_* w 2012. Zamiast tego powinieneś użyć PDO lub MySQLi . Jak to napisać (z PDO):

// creates DB connection
$connection = new PDO('mysql:host=localhost;dbname=mydb;charset=UTF-8', 
                      'username', 'password');
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

// executes the procedure and creates select statement
$connection->exec('CALL get_rands(10)');
$statement = $connection->query('SELECT * FROM rands');

// performs query and collects all the info
if ($statement->execute())
{
    $tags = $statement->fetchAll(PDO::FETCH::ASSOC);
}

Aktualizacja

Jeśli wymaganiem jest uzyskanie nie tylko 10 losowych wyników, ale w rzeczywistości 10 UNIKALNYCH losowych wyników , wymagałoby to dwóch zmian w PROCEDURE :

  1. Tablica tymczasowa powinna wymuszać unikalność wpisów:

    CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
    

    Sensowne może być również zbieranie samych identyfikatorów, a nie wartości. Zwłaszcza jeśli szukasz 10 unikalnych artykułów, a nie tylko tagów.

  2. Po wstawieniu zduplikowanej wartości, cnt licznik nie powinien się zmniejszać. Można to zapewnić, dodając HANDLER (przed definicją LOOP ), co „złapie” podniesione ostrzeżenie i wyreguluje licznik:

    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;
    


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP mysql wstaw format daty

  2. Jak używać MySQLdb z Pythonem i Django w OSX 10.6?

  3. 3 sposoby na znalezienie pozycji podciągu w ciągu w MySQL

  4. Zaawansowane zapytanie MySql:Aktualizuj tabelę informacjami z innej tabeli

  5. MySQL, zaktualizuj wiele tabel za pomocą jednego zapytania