1

データベースから写真のあるランダムな記事を抽出しようとしています。

SELECT FLOOR(MAX(id) * RAND()) FROM `table` WHERE `picture` IS NOT NULL

私のテーブルは 33 MB の大きさで、1,006,394 個の記事がありますが、写真付きの記事は 816 個しかありません。私の問題は、このクエリに 0.4640 秒かかることです

これをもっと速くする必要があります。どんなアイデアでも大歓迎です。

PS 1.もちろん、idにインデックスがあります。2. ピクチャ フィールドにインデックスがありません。追加する必要がありますか?3. 商品名も商品番号もユニークですが、それは論外です。

テストセッションの結果。

@cHaoのソリューションは、画像付きのランダムなエントリの 1 つを選択するために使用すると高速になります (0.1 秒未満です。しかし、反対のことをしようとすると、画像なしでランダムな記事を選択すると遅くなります。2.. 3秒

@Kickstartのソリューションは、画像のあるエントリを検索しようとすると少し遅くなりますが、画像のないエントリを検索しようとするとほぼ同じ速度になります。平均0.149秒。

@ bob-kruithofの解決策は私にはうまくいきません。画像のあるエントリを検索しようとすると、画像のないエントリが選択されます。

そして@ganesh-bora、そうです、私の場合、速度の違いは約5..15倍です。

皆さんのご協力に感謝したいので、@Kickstart に決めました。

4

4 に答える 4

1

一致するレコードで値の範囲を取得し、その範囲内で一致するレコードを見つける必要があります。

このようなもの:-

SELECT r1.id
FROM `table` AS r1 
INNER JOIN (
    SELECT RAND( ) * ( MAX( id ) - MIN( id ) ) + MIN( id ) AS id
    FROM `table`
    WHERE `picture` IS NOT NULL
) AS r2
ON r1.id >= r2.id
WHERE `picture` IS NOT NULL
ORDER BY r1.id ASC
LIMIT 1

ただし、効率を高めるには、チェックしているフィールドのインデックスが必要です(つまり、pictureあなたの例では)

これがどのように機能するかの説明です。

サブセレクトは、画像のレコードの最小 ID と最大 ID の間にあるテーブルからランダム ID を見つけます。このランダム ID は、画像用である場合とそうでない場合があります。

このサブ選択から得られた ID は、メイン テーブルに対して結合されますが、>= を使用し、レコードがピクチャ レコードであることを指定する WHERE 句を使用します。したがって、id がランダム id 以上であるすべての画像レコードに対して結合します。最も高いランダム ID は、最も高い ID を持つ画像レコードの ID になるため、常にレコードが検索されます (画像レコードがある場合)。次に、ORDER BY / LIMIT を使用して、その単一の ID を戻します。

これには明らかな欠陥があることに注意してください。しかし、ほとんどの場合、それは無関係です。取得されたレコードは、完全にランダムではない場合があります。最小の ID を持つ画像が返される可能性は低いですが (RAND() が正確に 0 を返す場合にのみ返されます)、これが重要な場合は、結果のランダム ID を丸めることで簡単に修正できます。もう 1 つの欠点は、ID が全範囲の ID で漠然と均等に分散されていない場合、一部の ID が他の ID よりも頻繁に返されることです。たとえば、最初の 1000 個の ID が写真であり、最後の (3300 万番目) レコードまでは写真ではないという状況を考えてみましょう。ランダム ID は 3,300 万のいずれかになりますが、1000 以下でない限り、3,300 万番目のレコードが返されます。

于 2013-05-09T09:00:11.393 に答える
0

パフォーマンスのために、最初に画像列にインデックスを追加して、クエリの実行中に814レコードが一番上に並べ替えられるようにしてから、クエリを起動できます。

于 2013-05-09T08:54:11.897 に答える
0

他の誰かがどのように問題を解決しましたか?

mysql でランダムな行を選択するさまざまな方法について、この記事を参照することをお勧めします。

記事の修正例

SELECT name
FROM random JOIN
    ( SELECT CEIL( RAND() * (
        SELECT MAX( id ) FROM random WHERE picture IS NOT NULL
    ) ) AS id ) AS r2 USING ( id );

これはあなたの場合にうまくいくかもしれません。

効率

  • ユーザーキックスタートが述べたように:列にインデックスがありますpictureか?これにより、結果が少し早く得られる場合があります。
  • テーブルは最適化されていますか?
于 2013-05-09T08:58:00.957 に答える