2

4,000,000 レコードのテーブルがあります。(user_id int, partner_id int, PRIMARY_KEY ( user_id )) engine=InnoDB; というテーブルが作成されます。select100 レコードのパフォーマンスをテストしたい。次に、次のようにテストしました。

mysql> explain select user_id from MY_TABLE use index (PRIMARY)  where user_id IN ( 1 );
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | PRIMARY     | MY_TABLE | const | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set, 1 warning (0.00 sec)

これで結構です。ただし、このクエリは mysql によってバッファリングされます。したがって、このテストは最初のテストの後にノーになります。

次に、ランダムな値で選択するSQLを考えました。私は以下をテストしました:

mysql> explain select user_id from MY_TABLE use index (PRIMARY)  where user_id IN ( select ceil( rand() ) );
+----+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows    | Extra                    |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+
|  1 | PRIMARY     | MY_TABLE | index | NULL          | PRIMARY | 4       | NULL | 3998727 | Using where; Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+

しかし、それは悪いです。 Explainpossible_keys が NULL であることを示しています。そのため、完全なインデックス スキャンが計画されていますが、実際には以前よりも遅すぎます。

では、インデックスルックアップでランダム値を記述する方法を教えていただきたいと思います。

ありがとう

4

3 に答える 3

1

通常、SQL での使用rand()は、クエリを遅くする確実な方法です。ここでの一般的なテーマはORDER BY、ランダムなシーケンスを取得するために使用する人々です。インデックスを破棄するだけでなく、テーブル全体を読み取るため、処理が遅くなります。

ただし、あなたの場合、関数呼び出しがサブクエリにあるという事実は、外側のクエリが引き続きそのインデックスを使用できるようにする必要があります。そうではないという事実はかなり奇妙に思えます (そのため、質問に +1 票を与えました)。

私の理論では、おそらく MySQL のオプティマイザが間違っているのではないかと考えています。つまり、内部クエリの関数を見て、インデックスを使用できないと誤って判断しているのです。

これを回避するために私が提案できる唯一のことはforce index、必要なインデックスを使用するように MySQL をプッシュすることです。

于 2013-03-17T14:03:09.170 に答える
0

rand()の定義を参照してください。

私の理解が正しければ、データベースからランダムなレコードを取得しようとしています。その場合は、rand() の定義から:

LIMIT と組み合わせた ORDER BY RAND() は、一連の行からランダムなサンプルを選択するのに役立ちます。

SELECT * FROM table1, table2 WHERE a=b AND c<d -> ORDER BY RAND() LIMIT 1000;

于 2013-03-17T14:42:35.770 に答える
0

これは、MySQL オプティマイザの制限です。サブクエリが正確に 1 つの値を返すことを認識できないため、サブクエリが予測できない値を含む複数の行を返すと想定する必要があります。したがって、インデックス スキャンを実行するだけであると判断します。

回避策は次のとおりです。

mysql> explain select user_id from MY_TABLE use index (PRIMARY)  
where user_id = ( select ceil( rand() ) );

MySQL の RAND() 関数は範囲内の値を返すことに注意してください0 <= v < 1.0。CEIL() を実行すると、値 1 が得られる可能性があります。したがって、事実上、常に user_id=1 の行が得られます。テーブルにそのような行がない場合は、空のセットの結果が得られます。すべてのユーザーの中からランダムにユーザーが選ばれることは絶対にありません。

この問題を解決するには、rand() に個別の user_id 値の数を掛ける必要があります。そして、ギャップがある可能性があるという問題が発生するため、ランダムに選択された値は既存の user_id と一致しません。


あなたのコメントについて:

インデックス スキャンを取得すると、可能なキーは常に NULL として表示されます (つまり、"type" は "index" です)。

同様のテーブルで説明クエリを試しましたが、サブクエリが定数式であることをオプティマイザが認識できないようです。この制限を回避するには、アプリケーション コードで乱数を計算し、その結果をクエリで定数値として使用します。

select user_id from MY_TABLE use index (PRIMARY)  
where user_id = $random;
于 2013-03-17T14:54:49.333 に答える