sql >> データベース >  >> RDS >> Mysql

ランダムな結果を10個取得するためにwhile/loopを実行する

    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_*で記述された新しいコードはもうありません。 代わりに、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個のUNIQUEランダムな結果を取得することである場合 、その後、PROCEDUREに2つの変更が必要になります :

    1. 一時テーブルは、エントリの一意性を強制する必要があります:

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

      値ではなくIDだけを収集することも理にかなっているかもしれません。特に、探しているのがタグだけでなく、10個のユニークな記事である場合。

    2. 重複する値を挿入すると、cnt カウンターは減少しないはずです。これは、HANDLERを追加することで確認できます。 (LOOPの定義前 )、発生した警告を「キャッチ」し、カウンターを調整します:

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


    1. MongoクラスターをSSLで保護する

    2. SQLiteSHOWTABLESと同等

    3. ミリ秒単位のCURRENT_TIMESTAMP

    4. Oracleで作成する前に、テーブルが存在するかどうかを確認してください