0

ゼロ以上の「カテゴリ」または「タグ」を持つことができる「もの」の単純なデータベースがあります。特定のカテゴリの最初の N 個のオブジェクトを取得するストアド プロシージャを作成しましたが、パフォーマンスは非常に良好です。それは何かのように見えます

SELECT * FROM things
WHERE things.datestamp > @start AND things.datestamp < @end
  AND EXISTS (
    SELECT 1 from thing_tags
    WHERE things.id = thing_tags.thing_id
      AND thing_tags.tag = @searchTag
  )
LIMIT ?

数十万の「もの」があり、それぞれに約 0 ~ 5 個のタグがあり、パフォーマンスは問題ありません。最初の数百の一致をせいぜい数十ミリ秒で取得できます。

ただし、一致する合計数を知りたい場合は、少なくとも数秒かかります。ただより賢い方法はありSELECT COUNT(id) FROM .... (rest of query above)ますか?この提案idに従って、フィールドにはインデックスが付けられていますが、 の各行のテーブルを検査する必要があるため、インデックスはあまり役に立ちません。tagsthings

私はページネーションの実装を検討しており、LIMIT ?,?(またはLIMIT ? OFFSET ?)簡単にすることはわかっていますが、少なくとも予想される合計「一致」数の概算をユーザーに示すとよいでしょう。

4

5 に答える 5

2

私は次のように数えるべきだと思います

SELECT count(id) FROM things, things_tags
WHERE things.datestamp > @start AND things.datestamp < @end
  AND things.id=thing_tags.thing_id
  AND things_tags.tag = @searchTag
  GROUP BY things.id

(datestamp,id) のものと (id,tag) の thing_tags のインデックスを使用します。ここでは、それぞれのタグが異なると仮定しています。

于 2013-08-15T12:02:38.517 に答える
1

あなたのコメントから、いくつかのオプションがあり、すべて長所と短所があります。

  1. 最適化を大幅に改善します。これには、インデックスと、データベースの少なくとも半分を RAM にロードすることが含まれます。信じてください、300K 行カウントは非常に高速です。ただし、RAM にはコストがかかり、調整には時間がかかります。

  2. ユーザーを完全な「次の 1 ~ 926」ではなく、「次の」のようなものとして表します。制限を 1 つ増やすだけで、最初に要求された行を提示するだけなので、実装は簡単です。あなたのデータベースがあなたが知っている +1 の結果を返す場合、あなたは NEXT を表す必要があります

  3. 制限 300 を要求するデータベースから、制限 100 の代わりに 2 をエクステントすることができます。そうすることで、ユーザーに +1 +2 +3 NEXT ボタンを与えることができます。

  4. どこかにカウントテーブルを作成して、テーブルを非正規化します。基本的に、それがデータ ウェアハウスの役割です。更新モードでは見苦しくなりますが、機能します。私が「醜い」と言うとき、私は醜いことを意味するので、私は通常、そのような演習を避けようとします.

  5. 説明するために行き、説明することは孤独な果実には役立たないという事実を受け入れてください。これは、*10 *100 *1000 *10000 *100000 についてのアイデアを得ることです。

  6. これらのオプションを組み合わせます。3 と 5 で、5 は核心的なグラフィック インジケーターに支払い、3 はユーザーにアクションを実行するためのフックを提供します。

  7. 「意味がありますか」という質問をします。これは哲学的になる可能性があり、私はあなたの考えを炎上させたくありません. しかし、300 K のアイテムをグループ化するタグは本当に意味があるのでしょうか? あなたが行くことができる概念的なトレードオフはありますか?

  8. 少しの再設計がオプションであるかどうかを検討してください。以前の会話から、thing_tags テーブルに同じものに対して同じタグ文字列の複数 (300K 以上) の行を格納していることを理解しました。つまり、非正規化された文字列バスケットがあり、インデックス作成またはインデックス メモリの使用率が低下し、どちらもパフォーマンスが低下します。タグ文字列をタグ テーブルに配置してから、「bridge」/n:n テーブル tag2thing を作成します。フィールドは tagid と thingid のみです。完了したら、ステートメントを分割するのが理にかなっています: 1. タグの ID を検索し、次に 2. tag2things と Things テーブルの結合をカウントします。

于 2013-08-15T14:57:41.247 に答える
1

こんにちは、私は Cloudspace で働いています (あなたがリンクしたブログ記事を書いたのは私たちです)。

1 つのアプローチは、thingsテーブルを変更してtags_count列を追加することです。次に、 を作成または破棄するthing_tagsたびに、更新クエリを追加して、適切な をインクリメントまたはデクリメントしますthing

これにより、次のようなカウントを選択できます

SELECT SUM(tags_count)
FROM things
WHERE things.datestamp > @start AND things.datestamp < @end

これはより速く、適度に正確でなければなりません。

どの言語/フレームワークを使用しているかはわかりませんが、たまたま Ruby on Rails を使用している場合、Rails はこのビルトイン(counter_cache と呼ばれる) をサポートしています。


編集:あなたも によって制限していることに気付いた@searchTagので、その場合に上記の私の提案がどれほど役立つかわかりません。

おそらく、あなたはこのようなことをすることができますか?これは、との間のthing_tags一致@searchTagと をカウントします。thing@start@end

SELECT count(thing_tags.id)
FROM thing_tags
  INNER JOIN things
    ON thing_tags.thing_id = things.id
WHERE things.datestamp > @start
  AND things.datestamp < @end
  AND thing_tags.tag = @searchTag
于 2013-08-15T19:04:59.463 に答える