2013-05-18 20 views
6

この質問のタグ付きデータベーススキーマを使用してanswerを使用すると、大量のデータで動作するgroup_concatを使用してクエリを実行できますか?私はタグxでタグ付けされたすべての項目のタグを持つ項目を取得する必要があります。 ~500万のタグを持つgroup_concatでのクエリを使用すると、> 15秒で非常に遅くなります。 group_concat(項目なし、タグなし)は〜0.05秒です。group_concatによるタグ付け

副次的な質問として、どうすればこの問題を解決できますか?

+1

サンプルレコードを提供できますか? –

+0

だから、最大5つのタグに質問を限定することでこの問題を解決するようです。そして、タグを扱う際にGROUP_CONCAT()を全く使用していると思うのはなぜですか? – Barmar

+1

@Barmar:SO上のタグの制限はパフォーマンス上の理由ではなく、[質問に集中する](http://meta.stackexchange.com/a/34743)。 [SOのスキーマ](http://meta.stackexchange.com/a/2678)では、タグは正規化された方法(PostTags'テーブル)と非正規化された方法(Posts.Tags 'フィールド) - 後者は、ポスト自身でポストのタグを検索するのが非常に速くなりますが、前者は特定のタグの組み合わせを持つポストを簡単に検索できます。 – eggyal

答えて

5

これは、おそらくインデックス作成戦略が悪い場合です。 ; MySQLのSERIALデータ型のような、インデックス化され、BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUEの別名であると

  • :という

    CREATE Table Items (
        Item_ID SERIAL, 
        Item_Title VARCHAR(255), 
        Content TEXT 
    ) ENGINE=InnoDB; 
    
    CREATE TABLE Tags (
        Tag_ID  SERIAL, 
        Tag_Title VARCHAR(255) 
    ) ENGINE=InnoDB; 
    
    CREATE TABLE Items_Tags (
        Item_ID BIGINT UNSIGNED REFERENCES Items (Item_ID), 
        Tag_ID  BIGINT UNSIGNED REFERENCES Tags (Tag_ID), 
        PRIMARY KEY (Item_ID, Tag_ID) 
    ) ENGINE=InnoDB; 
    

    注:リンクする質問のthe accepted answerに示すスキーマを適応

  • Items_Tagsで外部キー制約を定義すると、外部キー列にインデックスが作成されます。

+0

うーん、私は同じインデックスを持っていると確信しています、今夜後でチェックします。 –

+0

@amiawizard:ニュースはありますか? – eggyal

3

私はnormalizedデータとdenormalizedデータ間のハイブリッドを持って提案します。
は、だから私は、次の非正規化の構造を行うだろうeggyalが提供する正規化された構造を使用して:列Tags

CREATE TABLE Items_Tags_Denormalized (
    Item_ID BIGINT UNSIGNED REFERENCES Items (Item_ID), 
    Tags  BLOB, 
    PRIMARY KEY (Item_ID) 
) ENGINE=InnoDB; 

あなたが対応するItem_IDのためにすべてのタグ(Tag_Title)を持っています。
は今、あなたはこれを達成するための2つの方法があります:

  • GROUP_CONCATを使用して、この表Items_Tags_Denormalizedを構築します定期的に実行するcronを作成したり、あなたに(スーツ何を利点:あなたが挿入または削除するときに余分な負荷をかけていませんItems_Tagsテーブル内;欠点:非正規化テーブルには、常に(あなたがcronを実行しますどのくらいの頻度に応じて)最新ではありません)

  • 挿入時にItems_Tagsテーブルのtriggersを作成し、最新に保つために、削除Items_Tags_Denormalizedテーブル(利点:非正規化t常に最新の状態になりますことができ;短所:あなたが挿入またはItems_Tagsテーブルで、削除、追加の負荷)

長所と短所を考慮し、ニーズに合ったどんなソリューションを選択。

Items_Tags_Denormalizedテーブルがありますので、は追加操作を行わずに読み取ることができます

+0

正規化されていない 'Tags'フィールドを' Items'テーブルに追加してみてはいかがですか? – eggyal

+0

別々のモデルを持つことが重要です:正規化されたものと非正規化されたものがありますが、あなたの解答は大丈夫ですが、設計上のpovからです。テーブルを再構築する必要があります。アイテムに非正規化タグの列を追加すると、テーブルのパフォーマンスが低下します:より大きなサイズ=より遅いクエリ – Stephan

1

なぜそれにgroup_concatを使用しますか?与えられたタグxについて、あなたは項目のリストを選択するのが速いと言った。アイテムのリストを見ると、すべてのタグが高速になるはずです。通常、何らかの制限がないのは、通常のウェブサイトでは1ページに100000のエントリが表示されないということです。

私がお勧めします:

drop temporary table if exists lookup_item; 

create temporary table lookup_item (item_id serial, primary key(item_id)); 

insert into lookup_item select i.id as item_id 
from items i 
where exists (select * from items_tags where item_id = i.id and tag_id = <tag_id>) 
and <other conditions or limits>; 

select * from lookup_item 
inner join items_tags it on it.item_id = i.id 
inner join tags t on t.id = it.tag_id 
order by i.<priority>, t.<priority> 

優先順位は、アイテムやタグの重要性のいくつかの種類のために、最後に修正することができます。

それから、あなたはタグ付きのすべてのアイテムを取得します。コード内の唯一の作業は、結果行に次の項目があるかどうかを確認することです。

1

私が正しく理解していれば、タグなしでクエリを高速化するのは、GROUP_CONCATだけではありません。 GROUP_CONCATの内部では、Tags.Tag_Titleを選択して、タグテーブルに強制的にアクセスします。

GROUP_CONCATItems_Tags.Tag_IDで実行して、私の理論をテストできます。

関連する問題