タイトルの「コンテンツ フィールドが MAX(id) フィールドと一致しないのはなぜですか」という質問に答えるには、非集計フィールドに対して返される値が MAX 値の行から取得されるという保証がないためです。見つかった。これは文書化された動作であり、これが期待される動作です。
他の DBMS はステートメントでエラーをスローします。MySQL はより緩く、1 つの行から値を取得していますが、MAX 値 (ID または日付) のいずれかが見つかった行であるとは限りません。
2 つの別個の集計式MAX(m.id)
とがありMAX(m.date)
ます。これらの値が同じ行から取得されるという保証はないことに注意してください。
他のデータベースのルールは、SELECT リスト内のすべての非集計式が GROUP BY に表示される必要があるというものです。(MySQL はそれについてより緩く、それを要件にしません。)
MAX 値を持つ行から値を返すようにクエリを「修正」する 1 つの方法は、インライン ビュー (クエリ) を使用して、MAX(id)
GROUP BY したいものでグループ化してから、JOIN を元に戻すことです。 table を使用して、行の他の値を取得します。
あなたの声明から、どの結果セットを返したいのか明確ではありません。最大の id を持つ行が必要で、最大の日付を持つ行も必要な場合は、次のようにすることができます。
SELECT m.id
, m.sender_id
, m.receiver_id
, m.date
, m.content
, l.username
, p.gender
FROM ( SELECT t.sender_id
, t.receiver_id
, MAX(t.id) AS max_id
, MAX(t.date) AS max_date
FROM messages t
WHERE t.receiver_id=3
GROUP
BY t.sender_id
, t.receiver_id
) s
JOIN messages m
ON m.sender_id = s.sender_id
AND m.receiver_id = s.receiver_id
AND ( m.id = s.max_id OR m.date = s.max_date)
LEFT
JOIN login_users l on l.user_id = m.sender_id
LEFT
JOIN profiles p ON p.user_id = l.user_id
ORDER BY m.date DESC LIMIT 0, 7
「s」としてエイリアス化されたインライン ビューは最大値を返し、「m」としてエイリアス化されたメッセージ テーブルに結合されます。
ノート
ほとんどの場合、アクセス プランが異なるため、 はJOIN (query)
よりもパフォーマンスが優れていることがわかります。IN (query)
EXPLAIN で計画の違いを確認できます。
パフォーマンスのために、インデックスが必要です
... ON messages (`receiver_id`, `sender_id`, `id`, `date`)
receiver_id には等価述語があるため、(フル スキャンの代わりに) 範囲スキャンを取得するには、それが先頭の列になる必要があります。次に列が必要ですsender_id
。これにより、MySQL が「ファイルソートを使用する」操作を回避して行をグループ化できるようになるためです。および列が含まれid
てdate
いるため、インライン ビュー クエリは、テーブル内のページにアクセスする必要なく、インデックス ページから完全に満たすことができます。(EXPLAIN には " Using where; Using index
" が表示されます。)
その同じインデックスは外部クエリにも適しているはずですがcontent
、テーブル ページから " " 列にアクセスする必要があるため、EXPLAIN はそのステップで "Using index" を表示しません。(" content
" 列は、インデックスに必要な長さよりもはるかに長い可能性があります。)