3

mysql バックエンドを使用して php で作成した、ユーザー向けのプライベート メッセージング システムがあります。システムは古いメッセージを削除しますが、通常は 500,000 を超えるメッセージを保持します。現在、すべてのデータが 1 つのテーブルに含まれています。

message_table
    message_id (int 11)
    message_from_id (int 11)
    message_to_id (int 11)
    message_timestamp (int 11)
    message_subject (varchar 50)
    message_text (text)

メッセージの大部分は非常に短いため、システムを次のように変更することを検討しています。

message_table
    message_id (int 11)
    message_from_id (int 11)
    message_to_id (int 11)
    message_timestamp (int 11)
    message_subject (varchar 50)
    message_short_body (varchar 50)
    message_text_id (int 11)

text_table
    text_id (int 11)
    text_body (text)

次に、短いメッセージが入力された場合は「message_short_body」の下に入力され、それより長い場合は「text_table」に追加され、「text_id」が「message_text_id」として保存されます。メッセージがアクセスされると、次のようになります。

SELECT * FROM message_table LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id IF message_table.message_text_id != 0 WHERE message_table.message_to_id = $user_id

「IF message_table.message_text_id != 0」を追加しましたが、そのようなことが可能かどうかわかりません。

原則として、これによりデータベースのサイズが縮小されるかどうか、またはクエリが高速化されるかどうかを判断できますか?

4

3 に答える 3

2

「IFmessage_table.message_text_id!= 0」を追加しましたが、そのようなことが可能かどうかわかりません。

に実際に行がない限りtext_id = 0text_tableこれを行う必要はありません。を省略してIF、次のクエリを使用するだけです。

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body,
       …
FROM message_table
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id
WHERE message_table.message_to_id = $user_id

パフォーマンスの観点から、条件を結合条件に追加すると、エンジンがより効率的に物事を最適化できる可能性があります。

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body,
       …
FROM message_table
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id
                    AND message_table.message_text_id != 0
WHERE message_table.message_to_id = $user_id

サブクエリを使用してアプローチを試すこともできます。

SELECT IF(message_text_id = 0, message_short_body, (
  SELECT text_table.message_short_body
  FROM text_table
  WHERE text_table.text_id = message_table.message_text_id)) AS body,
       …
FROM message_table
WHERE message_table.message_to_id = $user_id

これには、text_table必要がない場合に検索を実行しないという利点がありますが、長いメッセージを使用してケースごとに個別のクエリを実行するという欠点があります。上記のクエリの方が優れていると思いますが、よくわかりません。

原則として、これによってデータベースのサイズが減少するか、クエリが高速化されるかどうかを判断することは可能ですか?

ユースケースによって異なるため、ベンチマークを行う必要があります。ほとんどのクエリがテキスト以外のフィールドからデータを取得する場合、テーブルが小さいほどそれらのクエリが高速になり、パフォーマンスが向上します。一方、通常、メッセージの残りの部分と一緒に本文が必要な場合は、パフォーマンスが低下する可能性があります。

また、ベンチマークを使用して、上記のさまざまな選択肢を区別する必要があります。

データベースのサイズに関しては、おそらく増加が見られます。テキストデータのストレージ要件はほぼ同じですが、追加のテーブルのインデックスにはコストがかかります。

これが私のスキーマである場合は、を削除しmessage_text_id、代わりにの主キーとtext_table一致する主キーを使用しmessage_tableます。つまり、各キーはメッセージテーブルまたは両方のテーブルでのみ発生し、同じキーを持つ行は一緒に属します。メッセージが他のテーブルにあるかどうかは、これらの場合にに設定message_table.message_short_bodyすることでエンコードできます。NULL

于 2013-01-14T16:19:44.967 に答える
0

これを試して:

SELECT *, IFNULL(tt.text_body,  mt.message_short_body) textBody 
FROM message_table mt 
LEFT JOIN text_table tt ON tt.text_id = mt.message_text_id 
WHERE mt.message_to_id = $user_id;
于 2013-01-14T13:29:21.863 に答える
0

「IF message_table.message_text_id != 0」を追加しましたが、そのようなことが可能かどうかわかりません。

探しているクエリは次のようなものです。

SELECT
  IFNULL(t.text, m.short_text) AS text
  -- other columns may follow
FROM messages2 m
LEFT JOIN texts t on m.text_id = t.id
WHERE to_id = A_USER_ID

原則として、これによりデータベースのサイズが縮小されるかどうか、またはクエリが高速化されるかどうかを判断できますか?

はい、可能です!少なくともそれをテストすることができます。私はそれをしました。500.000 エントリのメッセージ テーブルでテスト シナリオを作成しました。それらの 10 分の 1 ごとに長いテキストがあります。メッセージの from_id と to_id は、ランダムに 50 人のユーザーから選択されます。

パート 1 : 速度

別のテキスト テーブルを使用する 2 回目の試行では、BIGGGGGG の速度が向上します。最初の試行の平均クエリ時間は約 1.6秒でした。2 番目はわずか0.28秒です!!!!

質問に答えるには: はい、高速です! :)

パート 2 : データベースのサイズ

すでに予想されているように、データベースのサイズはわずかに大きくなります。テキストからの追加のインデックスにより、データベースが約 10% 増加しました

結論: 大きなテキストを別のテーブルに格納することは良い考えです。あなたの場合、クエリのパフォーマンスが最大 80% 向上し、ディスク コストがわずかに ~10% 増加します。

于 2013-01-14T13:34:25.580 に答える