3

MySQL データベースに支えられた私の Web アプリケーションで、メッセージが複数のユーザー間の会話にグループ化されるメッセージング システムを提供したいと考えていますが、いくつかのニーズを満たすテーブル構造の設計に行き詰まっています。

  • 複数のユーザーが 1 つの会話に参加できます
  • ユーザーは会話に参加、閲覧、退出、削除できます
  • 受信トレイ ビューで生成されるクエリはできるだけ少なくする必要があります

ここで、多対多リレーションの最初の要件は、ジャンクション テーブルを使用して解決できます。しかし、受信トレイ ビューの選択クエリを作成するときに、非常に多くの問題が発生することが証明されています。

2 番目の要件も課題であることが判明しました。ユーザーが会話を離れた場合でも、古いメッセージを読むことができるようにする必要があります。会話に残っているユーザー間の新しいメッセージは、去ったユーザーと共有しないでください。最初に考えたのは、会話に木のような構造を使用することでした。ユーザーが会話に参加または退出するたびに、親会話への参照を使用して新しい会話が作成され、ジャンクション テーブル内の残りの参加者との新しい関係が作成されます。

3 番目の要件も些細なことではないようです。受信トレイ ビューには、参加者として特定のユーザーとの会話のリストが表示されます。また、会話ごとに追加情報を表示する必要があります。現在の参加者全員の名前、会話への最後の返信、およびその返信の作成者です。受信トレイ ビューは、メッセージが属している会話に関する追加情報を含むメッセージのリストと考えてください。

私の現在のアプローチは次のようになります。

CREATE TABLE `conversation` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `parentId` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `parentId` (`parentId`),
  CONSTRAINT `conversation_ibfk_1` FOREIGN KEY (`parentId`) REFERENCES `conversation` (`id`)
);
CREATE TABLE `participant` (
  `userId` int(11) unsigned NOT NULL,
  `conversationId` int(11) unsigned NOT NULL,
  `readAt` datetime DEFAULT NULL,
  PRIMARY KEY (`userId`,`conversationId`),
  KEY `conversationId` (`conversationId`),
  CONSTRAINT `participant_ibfk_2` FOREIGN KEY (`conversationId`) REFERENCES `conversation` (`id`),
  CONSTRAINT `participant_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`)
);
CREATE TABLE `reply` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `conversationId` int(11) unsigned NOT NULL,
  `userId` int(11) unsigned NOT NULL,
  `text` text NOT NULL,
  PRIMARY KEY (`id`),
  KEY `conversationId` (`conversationId`),
  KEY `userId` (`userId`),
  CONSTRAINT `reply_ibfk_2` FOREIGN KEY (`userId`) REFERENCES `user` (`id`),
  CONSTRAINT `reply_ibfk_1` FOREIGN KEY (`conversationId`) REFERENCES `conversation` (`id`)
);
CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
);

ここで壁にぶつかり、すべてのニーズを満たすソリューションが見つかりません。ここにいる誰かが、このデータベース設計にアプローチする方法についてアドバイスをくれるかもしれません。

4

1 に答える 1

0

ユーザーの活動

私はまだ接合テーブルを作成しますが、タプルにインデックスを付けます。

USER_CONV   
---------------
id_user 
id_conversation
active_flag
begin_flag              - flag indicating if id_first_reply == id_first_visible_reply
id_first_reply          - first reply in the conversation
id_first_visible_reply  - first visible for a given user
id_last_reply           - last visible for a given user, user if active_flag = false, otherwise NULL

index (id_user, id_conversation, active_flag) 


USER_REPLY
---------------
id_user
id_conversaion
id_reply

index (id_user, id_conversation, id_reply) 

USER_CONV を使用すると、受信トレイを簡単に作成できます。それでも、USER_REPLY と結合し、次に REPLY と結合する必要があります。

受信トレイ

高速にしたい場合は、一種の CACHED_INBOX と、MOST_RECENT_USER_ACTIVITY を持つテーブルを作成します。CACHED_INBOX テーブルには、関連するデータを取得するために結合を行う必要のないすべての受信トレイ データが含まれますが、MOST_RECENT_USER_ACTIVITY からのデータで UNION を実行するだけで済みます。MOST_RECENT_USER_ACTIVITY は非常に小さい (高速に動作する) 必要があり、CACHED_INBOX は「静的」になります。その後、1 日に 1 回、または数日に 1 回、サーバーが使用される可能性が低い時間帯に CACHED_INBOX の一括更新を行います。ユーザーが永遠に会話にとどまることを決定しない限り、それは機能します。

最適化

もちろん、クエリオプティマイザーがインデックス作成をどのように使用するかを確認するには、少し説明する必要があります (使用する場合)。おそらく、ACTIVE_CONVERSATIONS のようなテーブルが必要になるでしょう。これにはインデックスがなく、パフォーマンスが少し低下します。ただし、その後、USER_CONV に対していくつかのバッチ更新を実行すると、より広範なインデックスが作成されます。少し試してみて、ユーザーの行動から何を期待するかを確認する必要があります。これは、アーキテクチャのドライバーの 1 つである必要があります。

注: 索引に関しては、索引付けのトピックに特化した優れた Web サイトがありますuse-the-index-luke.com

于 2014-03-17T20:23:09.553 に答える