2011-08-05 11 views
10

私は、アーティスト、アルバム、トラックの大きなデータベースを持っています。これらの各アイテムには、グルーテーブル(track_attributes、album_attributes、artist_attributes)を介して割り当てられた1つ以上のタグがあります。各項目タイプには数千(または数十万)のタグが適用されます。高性能多層タグのフィルタリング

私は2つのタスクを達成しようとしていますが、受け入れられるようにクエリを取得するのは非常に困難です。

タスク1)指定されたタグを持つアルバム(提供されている場合)に任意のタグ(提供されている場合)を持つアーティストによって、指定されたタグを持つすべてのトラックを取得します。結果はまた、タスク2アーティストまたはアルバムによってではなく、トラック

によって提示されている):タグの任意の集合(すなわちだけトラックタグは、いかなるアーティストやアルバムタグアクティブではない)

バリエーション存在しなくてもよいです前のフィルタの結果に適用されるタグのリストと、それぞれのタグが付いたトラックの数を取得します。

私が後にしているのは、アプローチの一般的なガイダンスです。私は一時テーブル、インナージョイント、IN()を試みましたが、これまでのすべての努力は遅い応答をもたらしました。私が後にした結果の良い例はここに見ることができます:http://www.yachtworld.com/core/listing/advancedSearch.jspを除いて、彼らはタグの1つの層しか持っていません、私は3つを扱っています。

表構造:

Table: attribute_tag_groups 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
name  | character varying(255)  | 
type  | enum (track, album, artist) | 

Table: attribute_tags 
    Column      |   Type    | 
--------------------------------+-----------------------------+ 
id        | integer      | 
attribute_tag_group_id   | integer      | 
name       | character varying(255)  | 

Table: track_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
track_id | integer      | 
tag_id  | integer      | 

Table: artist_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
artist_id | integer      | 
tag_id  | integer      | 

Table: album_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
album_id | integer      | 
tag_id  | integer      | 

Table: artists 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
name  | varchar(350)    | 

Table: albums 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
artist_id | integer      | 
name  | varchar(300)    | 

Table: tracks 
    Column |   Type    | 
-------------+-----------------------------+ 
id   | integer      | 
artist_id | integer      | 
album_id | integer      | 
compilation | boolean      | 
name  | varchar(300)    | 

EDIT私はPHPを使用しています、と私は、スクリプト内の任意の並べ替えや他のhijinxを行うには反対しておりません、私の#1の懸念は、戻りの速さです。

+2

私たちが作業するための完全な* show create table *とあなたの現在の質問を含めないのはなぜですか? –

+0

MySQLまたはPostgreSQL?前者の場合、後者を使用する良い解決策が存在する場合、後者への切り替えが選択肢になる可能性がありますか? @Denis - MySQL。 –

+0

この時点でDBMSへの切り替えはオプションではありません。 –

答えて

2

おそらくデータを非正規化するようにしてください。構造は挿入/更新の負荷に対して最適化されますが、クエリには最適化されません。私が得たように、あなたは挿入/更新クエリよりもはるかに選択クエリを持っています。

は、正規化された構造にデータを保存する:あなたはこのような何かを行うことができる。例えば

あなたはおそらく

select * from aggregate where album_tags MATCH (track_tags) AGAINST ('rock') 

のようなSQLを使用したこのテーブルは、このテーブルを再構築* _tags列に

クエリをFULLTEXTインデックスを作成する必要があり、検索をspeadするために、この

track_id, artist_tags, album_tags, track_tags 
    1 , jazz/pop/, jazz/rock, /heavy-metal/ 

    or 

    track_id, artist_tags, album_tags, track_tags 
    1 , 1/2/, 1/3, 4/ 

ようagregateテーブルを作成します1日に1回増分します。あなたは試してみること

+0

私はこれを使って、パフォーマンスがどのように見えるかを調べています。アイデアありがとう! –

+0

...?結果は何ですか? –

+0

まだテーブルを構築してテストしています。私は消えません:D –

3

スピードが必要な場合は、Solr/Luceneを調べることをお勧めします。 Solrを呼び出してPHPから結果を解析することで、データを保存して素早く検索することができます。また、追加の利点として、面倒な検索もあります(正しく解釈すると、質問のタスク2です)。欠点は勿論、冗長な情報を持つ可能性があります(一旦DBに格納されると、一度Solrドキュメントストアに格納されます)。そしてセットアップに時間がかかります(まあ、あなたはDrupal Solrの統合から多くを学ぶことができます)。

SolrのPHPリファレンスドキュメントをチェックしてください。

PHPでSolrを使用する方法については、http://www.ibm.com/developerworks/opensource/library/os-php-apachesolr/の記事を参照してください。

+0

私はこれを聞いたことがない、それが何であるか分からない。私は自分の時間にそれを研究するつもりですが、私は自分の組織がこの接線で離れる財政的あるいは時間的な予算を持っていないことを私が気づいたことから知っています - 私たちはすでにこのプロジェクトの終わりに近づいています、私たちは既にデータベースの複製と新しいWebサーバーに取り組んでいます!しかし、入力をありがとう! –

+0

私はちょうど基礎を示す有用な記事を追加しました。 Solrは非常に強力で非常に高速です...あなたがそれに投げる情報を索引付けするにはしばらく時間がかかります。 – wimvds

+0

私はLuceneがSOのタグに今使っているものだと思います。 – JNK

0

もの:

  • あなたのquerysのボトルネックを探索するQuery Analyzerを使用してください。 (ほとんどの回では根本的なDBSは、かなりの最適化で素晴らしい仕事をしている)

  • あなたのテーブル構造が十分に正規化されているが、個人的な経験は、あなたが& subquerysに参加しないようすることができます構造にはるかに大きなパフォーマンスレベルをアーカイブできることを私に示しました。 。あなたの場合、私は1つのフィールドにタグ情報を格納することをお勧めします。 (これは基礎となるDBSのサポートが必要です)

これまでのところ、

2

私はあなたのプロジェクトにどれくらいのお金を費やしたいかによって大きく変わってくると考えています。厳密な条件を達成することは理論的に不可能なタスクもあります(例えば弱いサーバーを1つだけ使用するなど)。私はあなたのシステムをアップグレードする準備が整ったと仮定します。

まず、あなたのテーブル構造はJOINを強制します。高性能アプリケーションを書くときは可能ならば避けるべきだと思います。私は "attribute_tag_groups"がわからないので、私はテーブル構造を提案します:tag(varchar 255)、id(int)、id_type(enum(track、album、artist)) idはid_typeに応じてartist_id、track_id、またはalbum_idにすることができます。この方法では、1つのテーブルにすべてのデータを書き込むことができますが、ソースの方がはるかに多くのメモリを使用します。

次に、いくつかのデータベースの使用を検討する必要があります。各データベースがあなたのデータの一部のみを含んでいるならば、さらに多くの助けになります(それぞれの検索はより速くなります)。データベース間でデータを広げる方法を決めることは、かなり難しい作業です。タグの長さに関する統計を作成し、同様のtrac/artistの結果を取得し、参照コードにハードコードする長さの範囲を見つけることをお勧めします。

あなたはMySqlのチューニングを考慮する必要があります(私はあなたがそうしたと確信していますが、ただの場合) - すべてのテーブルはRAMに存在する必要があります - それが不可能な場合はSSDディスクやRAIDなどを取得してください。データベースのタイプ/設定も非常に重要です(MySqlは内部統計のボトルネックを表示することさえあります)。

この提案は気になるかもしれませんが、PHPがMySql自身で行うことができる計算をPHPにさせるのが良い場合もあります。 MySqlデータベースはスケールアップがずっと難しく、PHP処理用のサーバは数分で追加できます。そして、異なるPHPスレッドは異なるCPUコア上で動作することができます.MySqlには問題があります。いくつかの高度なモジュールを使用することで、PHPのパフォーマンスを向上させることができます(PHPスクリプトとハードコードのボトルネックを高速のCコードでプロファイルします)。

最後に、私は最も重要だと思います - のキャッシュを使用する必要があります。私はそれが本当に難しいことを知っていますが、本当に良いキャッシングシステムがなければ大きなプロジェクトはなかったと思います。あなたのケースでは、いくつかのタグは確かに他の多くの人気があるので、それは大いにパフォーマンスを向上させる必要があります。キャッシュとは、どれくらいの時間を費やすことができ、どれだけのリソースを使用できるかによって、すべての要求の99%がキャッシュを使用できるようにすることです。

他のデータベース/索引付けツールを使用すると役立ちますが、理論的なクエリ速度の比較(O(n)、O(nlog(n))...)を考慮して、このツールを使用するとパフォーマンスが低下することがあります(定数20%)が、アプリケーションの設計が複雑になり、その価値がない場合がほとんどです。

1

私の経験から、ほとんどの「遅い」MySQLデータベースには正しいインデックスやクエリがありません。だから私はまずこれらをチェックするでしょう:

  1. すべてのデータタルベのIDフィールドがプライマリインデックスであることを確認してください。念のため。
  2. すべてのデータテーブルに対して、外部IDフィールドとインデックスのインデックスを作成し、MySQLが検索で使用できるようにします。
  3. グルーテーブルの場合は、まず2つのフィールドに主キーを設定します(最初は件名、次にタグ)。これは通常の閲覧用です。次に、タグIDに通常のインデックスを作成します。これは検索用です。
  4. まだ遅いですか?あなたのテーブルにMyISAMを使用していますか?クイッククエリー用に設計されています。
  5. まだ遅い場合は、低速クエリでEXPLAINを実行し、クエリと結果の両方を質問に投稿してください。好ましくは、完全なデータベース構造のインポート可能なSQLダンプを使用します。
0

インデックスが正しく使用されているかどうかを確認してください。たぶん、MySQLは仕事に就いていません。 PostgreSQLは使い慣れているべきですが、複合体ではより良いパフォーマンスを示します状況。

完全に異なるトラックでは、Google map-reduceを使用して、本当に大容量のデータセットに新しいno-SQLデータベースを使用してください。これにより、複数のサーバーで分散検索を並行して実行できます。

+0

MongoDBのようなものはうまく動作します。 – wulfgarpro

関連する問題