1

私の Rails アプリケーションには、ユーザー データを含むさまざまなデータベース テーブルがあります。これらのテーブルの中には、多数の行 (場合によってはユーザーごとに 500,000 行) があり、頻繁にクエリが実行されます。テーブルに何らかのクエリを実行するたびに、現在のユーザーの user_id がクエリのどこかにあります。テーブルがユーザーと直接関係がある場合は直接、または他のテーブルを介して関係している場合は結合を介してです。

パフォーマンスを向上させるために、user_id を非正規化してすべてのテーブルに含める必要がありますか?


一例を次に示します。

  • アドレスはユーザーに属し、user_id を持っています
  • エンベロープはユーザーに属し、user_id を持っています
  • AddressesEnvelopes は Address と Envelope を結合するため、envelope_id と address_id があります。user_id はありませんが、envelope または address (同じユーザーに属している必要があります) のいずれかを介してアクセスできます。

一般的な高価なクエリの 1 つは、特定のユーザーのすべての AddressesEnvelopes を選択することです。これは、Address または Envelope のいずれかと結合することで実現できますが、これらのテーブルからは何も必要としません。または、このテーブルでユーザー ID を複製することもできます。


別のシナリオを次に示します。

  • レターはユーザーに属し、user_id を持っています
  • 受信者は Letter に属し、letter_id を持っています
  • RecipientOption は Recipient に属し、recipient_id を持っています

レターを介してアソシエーションを経由することでいつでもアクセスできますが、受信者と受信者オプションの両方で user_id を複製することは理にかなっていますか?


いくつかのメモ:

  • ユーザー間で共有されるオブジェクトはありません。関連オブジェクトの階層全体は、常に同じユーザーに属します。
  • オブジェクトのユーザー所有者が変わることはありません。
  • データベースはデータ集約型のアプリケーションであるため、データベースのパフォーマンスは重要です。多くのクエリと多くのテーブルがあります。

では、インデックスを作成するときに使用できるように、すべてのテーブルに user_id を含める必要がありますか? それとも設計が悪いのでしょうか?

4

3 に答える 3

2

複合主キーを使用する場合は、非正規化する必要がないことを指摘したいと思います。AddressEnvelop ケースのサンプル:

user(
    #user_id
)
address(
    #user_id
,   #addres_num
)
envelope(
    #user_id
,   #envelope_num
)
address_envelope(
    #user_id
,   #addres_num
,   #envelope_num
)

(# は主キー列を示します)

避けることができれば、私はこの設計のファンではありませんが、これらすべてのオブジェクトがユーザーに関連付けられているという事実を考慮すると、このタイプの設計では、データを比較的簡単に分割できます (論理的に、範囲を配置する複数のデータベースまたは複数のマシンを使用して、別々のテーブルまたは物理的にユーザーの数)

このタイプの設計で意味のあるもう 1 つのことは、クラスター化されたインデックスを使用することです (MySQL では、InnoDB テーブルの主キーはクラスター化されたインデックスから構築されます)。user_id が常にインデックスの最初の列になるようにすると、テーブルごとに、1 人のユーザーのすべてのデータがディスク上で近くに保存されます。これは、常にuser_idでクエリを実行する場合に最適ですが、別のオブジェクトでクエリを実行するとパフォーマンスが低下する可能性があります(その場合、提案したような重複がより良い解決策になる可能性があります)

とにかく、設計を変更する前に、まずスキーマが最適化されていること、および外部キー列に適切なインデックスがあることを確認してください。パフォーマンスが本当に重要である場合は、単純にいくつかのソリューションを試してベンチマークを行う必要があります。

于 2009-12-24T10:39:40.877 に答える
1

あなたが〜をするなら

a) 測定可能なパフォーマンスの改善を得る

b)データベースのどの部分が実際の正規化されたデータであり、どの部分が冗長な改善であるかを知る

それをしない理由はありません!

于 2009-12-24T10:28:29.540 に答える
1

実際に測定されたパフォーマンスの問題がありますか? 500 000 行はそれほど大きなテーブルではありません。選択がそれほど複雑ではなく、列に適切なインデックスがある場合、選択は合理的に高速である必要があります。

最初に遅いクエリがあるかどうかを確認し、インデックスを使用してそれらを最適化しようとします。それでも十分でない場合は、非正規化を検討します。

他の手段で必要なパフォーマンスを達成できない場合、提案する非正規化は妥当と思われます。非正規化フィールドを最新の状態に保つようにしてください。

于 2009-12-24T10:37:41.037 に答える