Mysql
 sql >> база данни >  >> RDS >> Mysql

Правете закъснение / цикъл, за да получите 10 произволни резултата

Моля, спрете да използвате ORDER BY RAND() . Просто спри. Тази операция има сложност от n*log2(n) , което означава, че времето, прекарано в заявка, ще нарасне "

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

Ако искате да генерирате произволни резултати, създайте съхранена процедура, която ги генерира. Нещо подобно (код, взет от тази статия , което трябва да прочетете):

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 ;

И за да го използвате, трябва да напишете:

CALL get_rands(10);
SELECT * FROM rands;

Що се отнася до изпълнението на всичко от страна на PHP, трябва да спрете да използвате древния mysql_* API. Той е на повече от 10 години и вече не се поддържа. Общността дори започна процес за отхвърлянето им. Не трябва да има повече нов код, написан с mysql_* през 2012 г. Вместо това трябва да използвате PDO или MySQLi . Колкото до това как да го напиша (със 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);
}

Актуализиране

Ако изискването е да получите не само 10 произволни резултата, но всъщност 10 УНИКАЛНИ произволни резултата , тогава ще са необходими две промени в PROCEDURE :

  1. Временната таблица трябва да налага уникалността на записите:

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

    Също така може да има смисъл да събирате само идентификатори, а не стойностите. Особено ако това, което търсите, са 10 уникални статии, а не само тагове.

  2. При вмъкване на дублирана стойност се намира cnt броячът не трябва да намалява. Това може да се гарантира чрез добавяне на HANDLER (преди дефинирането на LOOP ), което ще „улови“ повдигнатото предупреждение и ще коригира брояча:

    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. Как да разделите низ в MySQL

  2. JSON_ARRAY_INSERT() – Вмъкване на стойности в JSON масив в MySQL

  3. Емотиконите за iPhone се вмъкват в MySQL, но стават празна стойност

  4. Използване на променлива env в application.properties на Spring Boot

  5. Най-ефективният начин за получаване на броя на редовете в таблицата