3

音楽アプリのスキーマデザインに問題があると思います。

私は3つのコレクションを持っています:Artists、、。および3つのクラス:、およびTracksAlbumsartistsalbumstracks

からのドキュメントartists

         [_id] => MongoId Object
            (
                [$id] => 4ee5bbfd615c219a07000000
            )
        [freeze] => false,
        [genres] => Array,
        [hits] => 0,
        [name] => Sarya Al Sawas,
        [pictures] => Array,

からのドキュメントalbums

        [_id] => MongoId Object
            (
                [$id] => 4ee88308615c218128000000
            )

        [name] => Sabia
        [slug] => wafiq-habib-ft-sarya-al-sawas-sabia
        [year] => 1999
        [genres] => Array,
        [pictures] => Array,
        [artists] => Array
            (
                [0] => MongoId Object
                    (
                        [$id] => 4ee34a3b615c21b624010000
                    )

                [1] => MongoId Object
                    (
                        [$id] => 4ee5bbfd615c219a07000000
                    )

            )

からのドキュメントtracks

            [_id] => MongoId Object
            (
                [$id] => 4ee8a056615c21542a000000
            )

        [name] => Bid Ashok
        [slug] => wafiq-habib-ft-sarya-al-sawas-bid-ashok
        [genres] => Array,
        [file] => /m/tracks/t.4ee8a05540c624.04707814.mp3,
        [freeze] => false,
        [hits] => 0,
        [duration] => 303,
        [albums] => Array
            (
                [0] => MongoId Object
                    (
                        [$id] => 4ee5cbc3615c216509000000
                    )

            )

        [artists] => Array
            (
                [0] => MongoId Object
                    (
                        [$id] => 4ee5bbfd615c219a07000000
                    )

                [1] => MongoId Object
                    (
                        [$id] => 4ee34a3b615c21b624010000
                    )

            )

まず第一に、その優れたスキーマ設計ですか??!多対多の関係があるため、このスキーマをこのように設計しました。トラックには2人のアーティストがいて、アルバムには2人のアーティストがいる場合があります。

とにかく、特定のトラックに添付されているアルバムのクエリに問題があります。

アーティストページにいるとしましょう

  1. すべてのアーティストのアルバムとトラックを取得する必要があるので、これを行います。

    $cursors = array(
        'albums' => $this->albums->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
        'tracks' => $this->tracks->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
        'clips'  => $this->clips->find(array('artists' => $artist->_id))->sort(array('_id' => -1))
    );
    foreach($cursors as $key => $cursor) {
        foreach($cursor as $obj) {
            $obj['name'] = ($this->lang->get() != 'ar' ? $obj['translated']['name'] : $obj['name']);
            $obj['by']   = $this->artists()->get($obj['artists'])->toString('ft');
            ${$key}[]    = $obj;
        }
    }
    
  2. すべてのトラックをループしてアルバム名を取得する必要があります。このアーティストには3000トラックあるとしましょう。非常に遅いと思いますが、...

だから私の質問は:それは良いスキーマ設計ですか?

4

1 に答える 1

3

まあ、これは非常にリレーショナルな問題であり、そのような問題に非リレーショナルデータベースを使用するには、いくらかの努力が必要です。一般的に、あなたのスキーマ設計は良いと思います。

あなたが説明していることは「N+1問題」と呼ばれます。なぜなら、N個のオブジェクトに対してN + 1クエリを実行する必要があるからです(あなたの場合、それはもっと複雑ですが、あなたはその考えを理解していると思います)。

いくつかの救済策:

  • 演算子を使用して、$inたとえば特定のアーティストのすべてのトラックを検索できます。

    db.tracks.find({"artists" : { $in : [artist_id_1, artist_id_2, ...] } });
    

    アーティストの数が膨大になった場合、これは機能しませんが、数百、おそらく数千が正常に機能するはずです。artistsインデックスが付けられていることを確認してください。

  • 非常に頻繁に必要となる情報の一部を非正規化することができます。たとえば、トラックリストを頻繁に表示したい場合は、アーティストの名前をすべてのトラックにコピーするのが理にかなっています。非正規化は、主にエンドユーザーの観点から達成しようとしていることに依存します。すべてのアーティストの名前を完全に保存するのではなく、UIが概要に表示されないため、最初の50文字だけを保存することをお勧めします。

    実際、アルバムのアーティストIDなどの一部のデータはすでに非正規化されています(トラックからも取得できるため、冗長です)。これによりクエリが簡単になりますが、書き込みが多くなります。更新がシステム全体に伝播することを確認する必要があるため、更新は醜いです。

  • 場合によっては、サーバーではなくクライアント(!)に「参加」する方が理にかなっている場合があります。これは実際には問題にうまく適合しませんが、注目に値します。友達のリストがあるとします。これで、サーバーは、表示されるたびに各友達の名前を検索する必要があります。代わりに、ルックアップテーブルID /フレンドを提供することができ、サーバーはIDのみを提供します。一部のJavaScriptは、IDをクライアントのキャッシュからの実際の名前に置き換えることができます。

于 2011-12-14T15:12:08.920 に答える