2017-11-14 7 views
1

私は2つのテーブルイベントとuser_deviceを持っています。 eventsおよびuser_deviceは共通フィールドdevice_idを持っています。結合テーブルで最後の5行を取得する必要があるクエリを最適化する方法

user_deviceテーブルには、フィールドuser_iddevice_idがあります。基本的に、すべてのデバイスを保持するuser_deviceテーブルはユーザに属します。

eventsすべてのイベントを保持するテーブルは、デバイスに属します。

今、特定のユーザーのアラートを5回取得したいと考えています。

私は以下のように両方のテーブルを結合してクエリを作成しました。

SELECT * 
FROM events 
LEFT JOIN user_device ON user_device.deviceid=events.deviceid 
WHERE user_device.userid=101 
ORDER BY events.id DESC 
LIMIT 5 

イベントテーブルには400万件を超えるレコードがあります。このクエリは結果を返すのに30秒かかります。

ORDER BYを削除すると、クエリにはわずか2秒しかかかりません。

これをどのように最適化できますか?

+0

特定のレコードを取得した場合は、手動で書き込みし、クエリから '* 'を削除してください。 – Bhargav

+1

クエリのパフォーマンスに関するセクションに特に注意して読んでください。 http://meta.stackoverflow.com/a/271056/質問を編集して詳細を入力してください。 –

答えて

0

テーブルにインデックスがないため、これが通常よりも長くかかるという事実があります。 deviceIdのインデックスを追加すると、userIdはクエリの速度に大きく役立ちます。

SELECT * 
FROM events 
LEFT JOIN user_device ON user_device.**deviceid**=events.**deviceid** 
WHERE user_device.**userid**=101 
ORDER BY events.id DESC 
LIMIT 5 

太字のテキストには、「フック」のインデックスが必要です。 Order byはインデックスを要求しません。

+0

Thanks @ naveed-ramzan – LahiruTM

1

SELECT *を使用しないでください。代わりに、必要な列の名前を付けます。

第2user_device.useridに一致するものを探しています。したがってuser_deviceのインデックスはuseridの列で始まる必要があります。同じテーブルにdeviceidの値を使用しています。したがって、このインデックスを作成します。それはcovering indexと呼ばれています。

ALTER TABLE user_device ADD INDEX x_user_device (userid, deviceid); 

サード:あなたはその後、idにより発注、deviceidによってevents内の行を探しています。したがって、これら2つの列に別のcovering indexが必要です。

ALTER TABLE events ADD INDEX x_device_id (deviceid, id); 

第四:あなたはWHERE句であなたのLEFT JOINしたテーブルの列に言及します。これはLEFT JOINを通常の内部JOINに変換します。したがって、JOINを使用してください。

第5SELECT * ... ORDER BY ... LIMITは、悪名高いパフォーマンスの反パターンです。どうして?それはレコードの全面的な混乱を命じなければなりません、少数を除くすべてを捨てるためです。代わりにこれを試してください。まずサブクエリで関連するevents.idの値を取得します。

  SELECT events.id 
      FROM events 
      JOIN user_device ON user_device.deviceid=events.deviceid 
      WHERE user_device.userid=101 
      ORDER BY events.id DESC 
      LIMIT 5 

サブクエリをテストします。 5つの関連するイベントID値を与える必要があります。それは実際には非常に迅速に行う必要があります。次に、このサブクエリを使用して、2つのテーブルから必要な詳細を検索します。

SELECT events.*, user_device.*  /* not optimal. list only the columns you need */ 
    FROM (
      SELECT events.id 
      FROM events 
      JOIN user_device ON user_device.deviceid=events.deviceid 
      WHERE user_device.userid=101 
      ORDER BY events.id DESC 
      LIMIT 5 
     ) sel 
    JOIN events ON sel.id = events.id 
    JOIN user_device ON events.deviceid = user_device.deviceid 

これは、遅延結合クエリパターンと呼ばれます。 idの値だけをすべて並べ替えて、いくつかのレコードを取り出します。

これは、データベースの拡大に合わせてパフォーマンスをチェックするのに役立ちます。

+0

ありがとうございます@ O.Jones。この説明は私を助けました。 – LahiruTM

関連する問題