実行に7秒かかる以下のクエリがあります
SELECT COUNT(*) AS `count`
FROM `yuldi`.`businesses` AS `Business`
LEFT JOIN `yuldi`.`businesses_categories` AS `BusinessesCategory`
ON (`Business`.`id` = `BusinessesCategory`.`business_id`)
LEFT JOIN `yuldi`.`categories` AS `Category`
ON (`BusinessesCategory`.`category_id` = `Category`.`id`)
WHERE `Category`.`slug` = 'building-construction'
2回目に実行すると160ミリ秒かかります。毎回1回目の実行で時間がかかる理由
説明:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | Category | const | PRIMARY,UNIQUE_SLUG,index_lug | UNIQUE_SLUG | 302 | const | 1 | Using index |
| 1 | SIMPLE | BusinessesCategory | ref | PRIMARY,fk_businesses_has_categories_categories1_idx,fk_businesses_has_categorie_businesses_idx | fk_businesses_has_categories_categories1_idx | 4 | const | 49630 | Using where; Using index |
| 1 | SIMPLE | Business | eq_ref | PRIMARY | PRIMARY | 4 | yuldi.BusinessesCategory.business_id | 1 | Using index |
やり直す必要がある3つの側面があります
クエリをご覧ください
SELECT COUNT(*) AS `count`
FROM `yuldi`.`businesses` AS `Business`
LEFT JOIN `yuldi`.`businesses_categories` AS `BusinessesCategory`
ON (`Business`.`id` = `BusinessesCategory`.`business_id`)
LEFT JOIN `yuldi`.`categories` AS `Category`
ON (`BusinessesCategory`.`category_id` = `Category`.`id`)
WHERE `Category`.`slug` = 'building-construction';
LEFT JOINを実行しています。これは、COUNTを実行する場合には必要ありません。どうして ?
ビジネスの数を数える場合は、1つのテーブルから数えるだけで済みます
SELECT COUNT(*) AS `count`
FROM `yuldi`.`businesses` AS `Business`;
Category.slug
にWHERE句があるため、JOINが必要です。 LEFT JOINからINNER JOINに切り替える必要があります。これにより、内部の一時テーブルが小さくなります。その一時テーブルは、スラッグ「building-construction」を検索します。
EXPLAINプランから、同じ名前の2つのインデックスが見られます
それらの列を見て、列リストが同一でないことを確認する必要があります。
2つのインデックスを作成することができます
ALTER TABLE BusinessesCategory
ADD INDEX bus_cat_ndx (business_id,category_id),
ADD INDEX cat_bus_ndx (category_id,business_id)
;
複合インデックスを使用すると、JOIN情報のテーブルでのカリングが少なくなります。
データの主要な分布がわからないため、この提案は盲目的です。
インデックス統計の収集は、クエリの評価が遅いクエリにすぐに変換されないためです。その遅さは本当の犯人によって明らかにされています:[〜#〜]キャッシング[〜#〜]。 2回目にクエリが速く実行される理由は、最初に読み取ったデータに関係しています。クエリを発行したときに、MySQLのキャッシュに必要なデータが含まれていない可能性があります。
MySQLの2つのメインキャッシュは、InnoDBバッファープール(InnoDBテーブルにヒットするクエリ用)とMyISAMキーキャッシュ(MyISAMテーブルにヒットするクエリ用)です。
InnoDBはデータとインデックスページをキャッシュしますが、MyISAMはインデックスページのみをキャッシュします。
比較のためにデータを取得するとき、mysqldは必要なデータがRAMに最初にあるかどうかを判断しようとします。これを監視するサーバーステータス変数があります:
クエリが初めて遅い場合は、クエリに必要なデータがキャッシュになかったことを意味します。これは、 Innodb_buffer_pool_reads または Key_reads の増分によって示されます。
2回目は、同じクエリのデータページまたはインデックスページ、あるいはその両方がRAMにあり、クエリや他のクエリからより多く利用できます。
InnoDBバッファープールおよび/またはMyISAMキーキャッシュ のサイズを確認することをお勧めします。