2017-01-12 6 views
-1

私は、「午前」のチャット(「普通」と「サービス」の両方)からuser.id = 1のすべてのメッセージ(着信と発信) 'イベントMySQLは、ほぼ同じ選択でプライマリキーがどこにあるかを最適化します

このディスプレイそれら(添付画像の選択1)

SELECT * 
FROM `message` 
JOIN chat 
ON message.chat_id = chat.id 
JOIN event 
ON chat.event_id = event.id 
JOIN chat_type 
ON chat.chat_type_id = chat_type.id 
WHERE (sender = 1 or recipient = 1) 
AND event.name = 'morning' 

しかし、私は除外しなければならない 『私は、送信者午前サービス』メッセージを。 これはうまく動作しますが、私はそれ(画像上の選択2)

SELECT * 
FROM `message` 
JOIN chat 
ON message.chat_id = chat.id 
JOIN event 
ON chat.event_id = event.id 
JOIN chat_type 
ON chat.chat_type_id = chat_type.id 
WHERE (sender = 1 or recipient = 1) 
AND event.name = 'morning' 
AND message.id NOT IN (
    SELECT message.id 
    FROM `message` 
    JOIN chat 
    ON message.chat_id = chat.id 
    JOIN event 
    ON chat.event_id = event.id 
    JOIN chat_type 
    ON chat.chat_type_id = chat_type.id 
    WHERE (sender = 1 or recipient = 1) 
    AND sender = 1 
AND chat_type.name = 'service' 
) 

スキーマを選択し、結果を好きではない:

enter image description here

+1

(あなたはまた、明示的に選択されている属性を呼び出す必要があります)あなたが好きではないのはなぜ溶液?走るのにどれくらい時間がかかりますか?いくつのレコードがありますか?クエリを最適化したい場合、plsは影響を受けるテーブルのすべてのインデックスとクエリの説明の結果を共有します。 – Shadow

+0

まだ多くのフィールドがありません;)プライマリキーフィールドと外部キーフィールドのみがインデックスされました。 IF-ELSEはサブクエリの代わりにwhere節を使うことができると思いますが、何百万行も高速で動作するのは面白いですね。 – Xitroff

答えて

0

あなたが持っているソリューションを好きではない理由を説明する必要があります。

あなたの説明と例から、サブ選択は、冗長とinnefficientです:

SELECT * 
FROM `message` 
JOIN chat 
    ON message.chat_id = chat.id 
JOIN event 
    ON chat.event_id = event.id 
JOIN chat_type 
    ON chat.chat_type_id = chat_type.id 
WHERE (message.sender = 1 or message.recipient = 1) 
AND event.name = 'morning' 
AND NOT (
    message.sender = 1 /* or whatever your id is */ 
    AND chat_type.name = 'service' 
); 

+0

ありがとう、あなたは信じられませんが、私は "NOT"を忘れてしまった;) – Xitroff

0

は、私が代わりに中or条件のunionを使用しますwhereの条件を満たしていれば、サブクエリなしでフィルタリングできます。

(
     SELECT * 
      FROM `message` 
      JOIN chat ON message.chat_id = chat.id 
      JOIN event ON chat.event_id = event.id 
      JOIN chat_type ON chat.chat_type_id = chat_type.id 
      WHERE sender = 1 
       AND event.name = 'morning' 
       AND chat_type.name <> 'service' 
    ) 
    UNION 
    (
     SELECT * 
      FROM `message` 
      JOIN chat ON message.chat_id = chat.id 
      JOIN event ON chat.event_id = event.id 
      JOIN chat_type ON chat.chat_type_id = chat_type.id 
      WHERE recipient = 1 
       AND event.name = 'morning' 
    ) 

現在、or操作を満たすためにインデックスを使用することはできません。したがって、unionを使用するのが一般的な最適化手法です。また、chat_typeテーブルをクエリから除外し、代わりにchat_type_id<>2にフィルタすることも検討します。同じ行に沿って、eventテーブルも削除できます。このテーブルを保持することに決めたとしても、テキスト値ではなく数値IDフィールドでフィルタリングを行う必要があります。

代わりに、サブクエリなしでフィルタリングを行うためにあなたのor条件を微調整することができます

SELECT * 
    FROM `message` 
    JOIN chat ON message.chat_id = chat.id 
    JOIN event ON chat.event_id = event.id 
    JOIN chat_type ON chat.chat_type_id = chat_type.id 
    WHERE ((sender = 1 
         AND chat_type.name <> 'service') 
       or recipient = 1 
      ) 
     AND event.name = 'morning' 
関連する問題