7

Ruby onRails3.2.2とMySQLを使用しています。インスタンスの「組み合わせ」ごとに、他の2つのクラスに関連するすべてのレコードをクラスに関連するデータベーステーブルに格納することが「推奨」/「望ましい」かどうかを知りたいです。

つまり、私はモデルを持っUserていArticleます。ArticleUserAuthorizationすべてのユーザー記事承認オブジェクトを保存するために、N人のユーザーとM人の記事が与えられたときにN*MArticleUserAuthorizationレコードが存在するようにモデルを実装したいと思います。

そうすることで、私は次のように述べて使用することができActiveRecord::Associationsます:

class Article < ActiveRecord::Base
  has_many :user_authorizations, :class_name => 'ArticleUserAuthorization'
  has_many :users, :through => :user_authorizations
end

class User < ActiveRecord::Base
  has_many :article_authorizations, :class_name => 'ArticleUserAuthorization'
  has_many :articles, :through => :article_authorizations
end

ただし、すべての組み合わせを格納する上記のアプローチでは、数十億の数十億の行を含む大きなデータベーステーブルが作成されます!!! さらに、理想的には、またはオブジェクトが作成されたときにすべての承認レコードを作成することを計画しています(つまり、前述のすべての「組み合わせ」を一度に作成するか、より適切には「遅延」バッチで作成することを計画しています...とにかく、このプロセスは他の数十億のデータベーステーブル行を作成します!!!)そして破壊するときにその逆を行います(数十億のデータベーステーブル行を削除することによって!!!)。さらに、orオブジェクトが更新されたときに、これらの行を一度に読み取って更新することを計画しています。UserArticleUserArticle

だから、私の疑問は次のとおりです。

  • このアプローチは「推奨」/「望ましい」ですか?たとえば、どのようなパフォーマンスの問題が発生する可能性がありますか?または、非常に大きなデータベーステーブルを持つデータベースを管理/管理するための悪い「方法」/「処方箋」ですか?
  • 私の場合、どのように/できます/すべきですか(おそらく、ユーザー認証をより良い方法で処理する方法を「再考」することによって)?

:オブジェクトを取得するときに「承認されたオブジェクト」のみUserを取得するには、「アトミック」ユーザー承認ルール(つまりArticle、ユーザーと記事オブジェクトごとに1つのユーザー承認レコード)が必要であるため、このアプローチを使用します。システムは、「admin」、「registered」などのユーザーグループに基づいていません。ArticleUserAuthorizationしたがって、テーブルの可用性により、取得した各オブジェクトでユーザー承認に関連するメソッドを実行することを回避できると思いました(注:これらのメソッドには、パフォーマンスを低下させる可能性のあるMySQLクエリが含まれます- 「承認」メソッドの実装例については、前の質問を参照してください)。 「単に」アクセス/参加することによってArticleUserAuthorization「ユーザーが承認した」オブジェクトのみを取得するためのテーブル。

4

7 に答える 7

6

実際のところ、ユーザーごとに記事レベルのアクセス許可Userが必要な場合は、 をユーザーがアクセスできるに関連付ける方法が必要Articleです。これには、最低限必要な N*A が必要です (A は、一意に許可された記事の数です)。

これに対する3NFのアプローチは、あなたが示唆したように、UsersArticlesセットを持つことです...これは非常に大きなテーブルになります(あなたが指摘したように)。

このテーブルが頻繁にアクセスされることを考慮してください... これは、少し非正規化されたアプローチ (または noSQL) がより適切な状況の 1 つのように思えます。

Twitter がユーザー フォロワー テーブルに使用するモデルを考えてみましょう。

この件に関するジェフ・アトウッド

高スケーラビリティ ブログ

これらの部分のサンプルは、正規化されたテーブルからフォロワーをクエリすると、テーブルに多大なストレスがかかるという Twitter で学んだ教訓Usersです。彼らの解決策は、ユーザーのフォロワーが個々のユーザー設定に保存されるように、フォロワーを非正規化することでした。

多くの非正規化。独力で彼らを救った。たとえば、すべてのユーザー ID とフレンド ID を一緒に保存することで、多くのコストのかかる結合を防ぎました。- 複雑な結合を避ける。- 大規模なデータ セットのスキャンは避けてください。

同様のアプローチを使用して、記事のアクセス許可を提供し、非常にストレスの多いUsersArticles単一のテーブルを回避できると思います。

于 2012-06-22T15:29:14.380 に答える
5

車輪の再発明をする必要はありません。ACL(アクセス制御リスト)フレームワークは、今では同じ種類の問題を何年にもわたって処理しますが、私に言わせれば最も効率的です。リソース(記事)またはさらに優れたリソースグループ(記事カテゴリ/タグ/その他)があります。一方、ユーザー(ユーザー)ユーザーグループがあります。次に、リソースグループをユーザーグループにマップする比較的小さなテーブルが作成されます。そして、この一般的なマッピングの例外を保持する別の比較的小さなテーブルがあります。または、記事にアクセスするためのルールセットを設定することもできます。ユーザーとユーザーの関係に応じて、authors_friendsのような動的なグループを作成することもできます。

適切なACLフレームワークを見るだけで、この種の問題をどのように処理するかがわかります。

于 2012-06-25T19:01:49.113 に答える
4

「何十億もの行を含む大きなデータベーステーブル」の可能性が本当にある場合は、(比較的) まばらにデータが格納されたテーブルに関する特定のニーズに合わせたソリューションを作成する必要があります。

大規模なデータベース テーブルは、システムが関連する行をどれだけ迅速に見つけられるかという点で、重大なパフォーマンス上の問題を引き起こします。ここでは、インデックスと主キーが本当に必要です。ただし、ストレージ要件が追加され、レコードが追加、更新、および削除されるため、CPU サイクルを維持する必要もあります。それでも、負荷の高いデータベース システムには、このような行の場所のパフォーマンスの問題に対処するパーティショニング機能 ( http://en.wikipedia.org/wiki/Partition_(database ) を参照) もあります。

行が返されないときはいつでも何らかの (計算可能なまたは定数の) デフォルトを使用できると仮定すると、まばらにデータが取り込まれたテーブルはおそらく目的を果たすことができます。デフォルト以外のものが必要な場合にのみ、行を挿入します。データがまばらに存在するテーブルでは必要なストレージ スペースがはるかに少なくなり、システムはより迅速に行を見つけることができます。(ユーザー定義の関数またはビューを使用すると、クエリを簡単に行うことができます。)

まばらに入力されたテーブルをうまく機能させることが本当にできない場合は、かなり行き詰まっています。おそらく、その巨大なテーブルを小さなテーブルのコレクションにすることができますが、データベース システムがパーティショニングをサポートしている場合、それが役立つとは思えません。さらに、小さなテーブルのコレクションは、より複雑なクエリになります。

したがって、システム内の何百万または何十億もの記事に関して特定の特権を持っている、または持っていない可能性のある何百万または何十億ものユーザーがいるとしましょう。では、ビジネスレベルでは、ユーザーが特定の記事で何をする特権を与えられているかを決定するものは何ですか? ユーザーは (有料の) サブスクライバーでなければなりませんか? それともゲストでしょうか?ユーザーは特定の記事のパッケージを申請 (および支払い) しますか? ユーザーは特定の記事を編集する権限を与えられることがありますか? などなど。

では、特定のユーザーが特定の記事で何かをしたいとしましょう。まばらに入力されたテーブルの場合、SELECTそのグランド テーブルの UsersArticles は 1 行を返すか、何も返さないかのいずれかになります。行が返された場合、ArticleUserAuthorization がすぐにわかり、残りの操作に進むことができます。

行がない場合、ユーザーはこの記事で何もできないと言うだけで十分です。または、ユーザーは、何らかの ArticleAttribute (この記事が持っているか持っていない) を持つ任意の記事に対して特定の権限を付与されているユーザーグループのメンバーである可能性があります。または、Article には、UsersArticles にそのようなレコードをまだ持っていないユーザー用のデフォルトの ArticleUserAuthorization (他のテーブルに格納されている) があるかもしれません。または何でも...

ポイントは、多くの状況には、システムが必要とするリソースを削減するのに役立つ構造と規則性があるということです。たとえば、人間は、5 兆を超えるエントリのテーブルを参照することなく、それぞれ最大 6 桁の 2 つの数字を追加できます。それは構造を利用しています。規則性については、ほとんどの人がパレートの原則 (「80-20」ルール - http://en.wikipedia.org/wiki/Pareto_principleを参照) について聞いたことがあるでしょう。「何十億もの行」が本当に必要ですか? あるいは、ユーザーの約 80% はそれぞれ、おそらく数百または数千の記事に対して (特別な) 特権しか持っていないと言ったほうが正しいでしょうか。 .

于 2012-06-22T21:24:23.150 に答える
1

階層的な役割ベースのアクセス制御 (RBAC) ソリューションを検討する必要があります。賢明なデフォルトも考慮する必要があります。

  • デフォルトでは、すべてのユーザーが記事を読むことができますか? 次に、例外を保存しdenyます。

  • デフォルトでは、すべてのユーザーが記事を読むことを許可されていませんか? 次に、例外を保存しallowます。

  • allowデフォルトがかかは記事次第deny?次に、それを記事に保存し、allowdeny例外の両方を保存します。

  • 記事は号にまとめられ、号は雑誌にまとめられ、雑誌は知識の分野にまとめられますか? users次に、とそれらのオブジェクトの間で承認を保存します。

  • Useraが a の読み取りを許可されているJournalが、特定の を拒否されている場合はどうなりArticleますか? 次に store User-Journal:allowUser-Article:deny最も具体的な命令 (この場合は記事) がより一般的な命令 (この場合はデフォルト、およびジャーナル)よりも優先されます。

于 2012-06-28T12:49:02.380 に答える
0

すべてのコメントと質問を読んで、私はまだすべての組み合わせを保存することの妥当性を疑っています。別の方法で質問について考えてください-誰がそのテーブルにデータを入力しますか?記事の著者またはモデレーター、または他の誰か?そして、どのようなルールに基づいていますか?あなたはそれがどれほど難しいか想像してみてください。すべての組み合わせを設定することは不可能です。

Facebookにも同様の機能があります。あなたが投稿を書くとき、あなたはそれを誰と共有したいかを選ぶことができます。「友達」、「友達の友達」、「全員」、またはカスタムリストを選択できます。カスタムリストを使用すると、誰を含めたり除外したりするかを定義できます。それと同じように、「include」や「exclude」などの特殊なケースのみを保存する必要があり、残りのすべての組み合わせはデフォルトのケースに分類されます。これをドンすることにより、N*Mを大幅に減らすことができます。投稿の可視性

于 2012-06-28T06:21:01.080 に答える
0

ArticleUserAuthorization テーブルを user_id で分割します。原則は、アクセス パス上の有効なデータセット サイズを減らすことです。一部のデータは他のデータよりも頻繁にアクセスされ、特定の方法でアクセスされます。そのパスでは、結果セットのサイズは小さくする必要があります。ここでは、シャードを使用してそれを行います。また、読み取りワークロードの場合はインデックスを作成し、キャッシュするなどして、そのパスをさらに最適化します

この特定のシャードは、ユーザーによって承認されたすべての記事が必要な場合に役立ちます。
記事でもクエリを実行する場合は、テーブルとシャードを article_id で複製します。この 2 番目のシャーディング スキームがある場合、データは非正規化されています。データは複製され、アプリケーションはデータの一貫性を維持するために追加の作業を行う必要があります。書き込みも遅くなります。書き込みにはキューを使用してください

シャーディングの問題は、シャード間のクエリが効果がないことです。別のレポート データベースが必要になります。シャーディング スキームを選択し、シャードの再計算について検討します。

本当に大規模なデータベースの場合、複数の物理マシンに分割する必要があります。例えば。ユーザーの記事ごとに 1 台以上のマシン。

いくつかのnosqlの提案は次のとおりです。

  1. 関係はグラフです。グラフデータベースを見てください。特に
    https://github.com/twitter/flockdb
  2. リレーションシップをリストに保存することにより、redis。
  3. hbase のような列指向データベース。まばらなネストされたハッシュのように扱うことができます

これはすべて、データベースのサイズとクエリの種類によって異なります

編集:修正された回答。質問には以前に「had_one」関係がありましたまた、nosql の提案 1 と 2 を追加しました

于 2012-06-23T17:26:11.437 に答える
0

まず、デフォルト値と動作について考え、それらをデータベースに保存しないことをお勧めします。たとえば、既定では、指定しない限りユーザーが記事を読むことができない場合false、データベースに保存する必要はありません。

2 番目に考えたのは、テーブルにusers_authorizations列を、テーブルarticlesに を含めることができるということです。これらの 2 つの列には、ユーザー ID と記事 ID がフォームに格納されます。たとえばテーブルの場合、これは ID を持つユーザーが記事にアクセスできることを意味します。次に、そのようにユーザーを取得するようにクエリを変更する必要があります。articles_authorizationsusers3,7,65,78,29,78articles3,7,65,78,29,78

@article = Article.find(34)
@users = User.find(@article.user_authorizations.split(','))

記事とユーザーが保存または破棄されるたびに、コールバックを作成して承認列を更新する必要があります。

class User < ActiveRecord 
   after_save :update_articles_authorizations
   def update_articles_authorizations
     #...
   end
end

Articleモデルについても同じことを行います。

最後に: さまざまな種類の承認がある場合は、ためらわずに のような列をさらに作成してくださいuser_edit_authorization

これらの手法を組み合わせることで、DB へのデータとヒットの量は最小限に抑えられます。

于 2012-06-25T15:54:44.187 に答える