web-dev-qa-db-ja.com

外部キーにインデックスを追加すると、このMySQLクエリのパフォーマンスが向上しますか?

次のクエリについて考えてみます。

_SELECT
  `locations`.`id` AS `location_id`,
  `locations`.`address`,
  `locations`.`lat`,
  `locations`.`lng`,
  `tickets`.`status_id`,
  `customers`.`name`,
  `tickets`.`id` AS `id`,
  `tickets`.`updated_at` AS `updated_at`,
  ( 3959 * acos( cos( radians('39.78222851322262') ) * cos( radians( `lat` ) ) * cos( radians( `lng` ) - radians('-86.16299560000004') ) + sin( radians('39.78222851322262') ) * sin( radians( `lat` ) ) ) ) AS `distance`
FROM `locations`
RIGHT JOIN `tickets`
  ON (`tickets`.`location_id` = `locations`.`id`)
LEFT JOIN `customers`
  ON (`tickets`.`customer_id` = `customers`.`id`)
WHERE `tickets`.`client_id` = '20'
AND
  (
    `customers`.`name` LIKE '%Mahoney%'
    OR `customers`.`email` LIKE '%Mahoney%'
    OR `locations`.`address` LIKE '%Mahoney%'
  )
HAVING `distance` < '5'
ORDER BY `distance`
LIMIT 200;
_

プロファイリングツールを使用して、このレポートを取得しました。

_Speed: 45.569 ms
Query analysis:
· Query: SIMPLE on tickets · Type: ALL · Rows: 160 (Using where; Using temporary; Using filesort)
· Query: SIMPLE on locations · Possible keys: PRIMARY · Key Used: PRIMARY · Type: eq_ref · Rows: 1
· Query: SIMPLE on customers · Possible keys: PRIMARY · Key Used: PRIMARY · Type: eq_ref · Rows: 1 (Using where)
_

これはMySQLデータベースです。すべてのテーブルはutf8_unicode_ciを備えたInnoDBです。各テーブルの主キーはidと呼ばれ、インデックスが付いたint(11)です。

  • _tickets.location_id_および/または_tickets.customer_id_および/または_tickets.client_id_にインデックスを追加すると、このクエリのパフォーマンスが向上しますか?
  • なぜか、なぜそうでないのか?
  • このクエリの効率を向上させるためにインデックス作成を検討する必要がある他のフィールドはありますか?
  • データベーススキーマで外部キーを明示的に定義する必要がありますか?

最初に場所から選択するので、参照されている外部キーのインデックスが必要だと思います。私はここを読みます: インデックス、外部キーと最適化 MySQLはすべての外部キーのインデックスを必要としています。 InnoDBスキーマで外部キーを明示的に定義すると、パフォーマンスが向上しますか?そのような合計n00bであって申し訳ありません。助けてくれてありがとう!

2
Ben Harold
  1. はい、これらのインデックスを追加するとパフォーマンスが向上する可能性があります。ただし、このような行数が少ない場合、全表スキャンの方が効率的で、オプティマイザがインデックスを使用しないことを選択する可能性があります。
  2. インデックスを追加した後、実行プランは異なります。インデックスの効果の概算を取得するには、explainの出力の各行の「行」列を乗算します。
  3. 一般に、パフォーマンスを向上させることにより、フィルタリング/結合条件/順序/グループに参加するフィールドのインデックス。また、列の選択度(個別の値の数)を考慮する必要があります。値が低すぎると、クエリのインデックスをカバーしている場合を除き、エンジンはそれを使用しません。
  4. 外部キーは制約です。いくつかの制限を強制するための制約の主な目的(FKの場合は参照整合性)。したがって、データの整合性を重視する場合は、外部制約を追加する必要があります。

Mysqlが暗黙的にFK列にインデックスを作成するという事実は、読み取りパフォーマンスが向上し、挿入/更新/削除のパフォーマンスが少し低下することを意味します(インデックス自体を更新する必要があるため)。

最後に、

私は最初に場所から選択しているので、...

完全に正しくはありません。物理処理は論理処理と同じではありません。オプティマイザーは、関係するテーブルを処理する順序(出力からわかるように、エンジンは最初にticketsテーブルにアクセスします)と使用するアクセス方法を決定します。ヒントである程度制御できますが...

*サイドノート。 WHERE句の記述方法:

WHERE `tickets`.`client_id` = '20'
  AND
  (
    `customers`.`name` LIKE '%Mahoney%'
    OR `customers`.`email` LIKE '%Mahoney%'
    OR `locations`.`address` LIKE '%Mahoney%'
  )

LEFT JOIN customersINNER JOIN。*として動作させる

更新サイドノートを気にしないでください。複数のテーブルがあるORsがあることに注意していません。

お役に立てば幸いです。

3
a1ex07