sql >> Databáze >  >> RDS >> Mysql

Proveďte chvíli / smyčku, abyste získali 10 náhodných výsledků

Prosím, přestaňte používat ORDER BY RAND() . Přestaň. Tato operace má složitost n*log2(n) , což znamená, že čas strávený dotazem poroste "

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

Pokud chcete generovat náhodné výsledky, vytvořte uloženou proceduru, která je vygeneruje. Něco takového (kód převzat z tohoto článku , kterou byste si měli přečíst):

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 ;

A abyste jej použili, napsali byste:

CALL get_rands(10);
SELECT * FROM rands;

Pokud jde o spouštění všeho na straně PHP, měli byste přestat používat staré mysql_* API. Je více než 10 let starý a již neudržovaný. Komunita dokonce zahájila proces za jejich zavržení. Už by neměl být žádný nový kód napsaný pomocí mysql_* v roce 2012. Místo toho byste měli použít CHOP nebo MySQLi . Pokud jde o to, jak to napsat (s 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);
}

Aktualizovat

Pokud je požadavkem získat nejen 10 náhodných výsledků, ale ve skutečnosti 10 UNIKÁTNÍCH náhodných výsledků , pak by to vyžadovalo dvě změny PROCEDURE :

  1. Dočasná tabulka by měla vynutit jedinečnost položek:

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

    Také by mohlo mít smysl shromažďovat pouze ID, nikoli hodnoty. Zvláště pokud to, co hledáte, je 10 jedinečných článků, nikoli pouze tagy.

  2. Při vkládání duplicitní hodnoty je nalezen cnt čítač by se neměl snižovat. To lze zajistit přidáním HANDLER (před definicí LOOP ), který by „zachytil“ zvednuté varování a upravil počítadlo:

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


  1. Převeďte datum řetězce na datum a čas v Oracle

  2. Dotaz na dvě tabulky z jiného schématu

  3. Jak UPDATEXML() funguje v MariaDB

  4. Jak odstranit velká data tabulky v SQL bez protokolu?