2011-07-11 9 views
0

以下のMySQLクエリを使用して、イベントリストページのイベントを取得しています。問題は、制限10で実行するのに約35秒かかります。ページング用にCOUNTを実行するにはもう35秒かかります。 ページの読み込み時間が70秒以上になると、想像できるように、がカットされません。そして、これは740イベントの結果だけです!私は2000+以上になるとこれがどのように動くか考えるのは怖いです。複雑なマルチジョインズMySQLクエリの高速化(問題がある場合はCakePHP経由で作成されます)

私たちは索引付けを試みましたが(索引知識が欠けていない限り)、それは文字どおり効果がありませんでした。

テーブルアソシエーションの説明: イベントは、レストランまたは会場で開催することができます。そのイベントの都市は、開催されているレストランまたは会場のcity_idによって決定されます。また、アップロード(この場合は写真)も取得しています。

多少混乱する部分はスケジュール/日付です - スケジュールはイベントの開始/終了/繰り返し情報を保持します。日付のレコードはスケジュールの情報に基づいて作成され、イベントが開催されている毎日の個々のレコードを保持します(start = datetime、end = datetime)

私はこのクエリを作成するためにCakePHPを使用しています。底部のアソシエーション:

SELECT 
`Event`.*, `Venue`.`id`, `Venue`.`slug`, `Venue`.`name`, `Venue`.`GPS_Lon`, 
`Venue`.`GPS_Lat`, `Venue`.`city_id`, `VenueCity`.`name`, `VenueCity`.`slug`, 
`Restaurant`.`id`, `Restaurant`.`slug`, `Restaurant`.`name`, `Restaurant`.`GPS_Lat`, 
`Restaurant`.`GPS_Lon`, `Restaurant`.`city_id`, `RestaurantCity`.`name`, 
`RestaurantCity`.`slug`, GROUP_CONCAT(Date.start, "|", Date.end 

ORDER BY Date.start ASC SEPARATOR "||") AS EventDates 
FROM `events` AS `Event` 
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) 
LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`) 
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`) 
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`) 
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`) 
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`) 
LEFT JOIN uploads AS `Upload` ON (`Upload`.`event_id` = `Event`.`id`) 
WHERE `Event`.`approval_status_id` = 1 AND `Date`.`start` >= '2011-07-11 12:38:54' 
GROUP BY `Event`.`id` 
ORDER BY `Date`.`start` ASC LIMIT 10 

CakePHPのアソシエーション:

Event belongsTo Venue 
Venue hasMany Event 

Event belongsTo Restaurant 
Restaurant hasmany Event 

Event hasMany Upload 
Upload belongsTo Event 

City hasMany Restaurant 
City hasMany Venue 
Restaurant belongsTo City 
Venue belongsTo City 

Event hasMany Schedule 
Schedule belongsTo Event 
Schedule hasMany Date 
Date belongsTo Schedule 

UPDATE(@Zoredacheリクエストあたり):

これは私が選択する前にEXPLAIN追加することから得るものです:インデックスが正しいと仮定すると、

id select_type table   type possible_keys   key    key_len ref        rows Extra 
1 SIMPLE  Event   ref PRIMARY,approval status approval status 5   const       946 Using where; Using temporary; Using filesort 
1 SIMPLE  Restaurant  ref PRIMARY,id    id    4   medut_ent.Event.restaurant_id 1 
1 SIMPLE  Venue   ref PRIMARY,id    id    4   medut_ent.Event.venue_id  1 
1 SIMPLE  VenueCity  ref PRIMARY,id    id    4   medut_ent.Venue.city_id   1 
1 SIMPLE  RestaurantCity ref PRIMARY,id    id    4   medut_ent.Restaurant.city_id 1 
1 SIMPLE  Schedule  ref PRIMARY,index   index   5   medut_ent.Event.id    1  Using where; Using index 
1 SIMPLE  Date   ref all cols,start...  all cols   5   medut_ent.Schedule.id   8  Using where; Using index 
1 SIMPLE  Upload   ALL                      4240 
+0

説明を使って手動でクエリを実行しようとしましたか?重要なフィールドにインデックスを設定していますか? – Zoredache

+0

@ Zoredache - 私は必要と思ったすべてのフィールドのインデックスを作成しようとしました。 EXPLAINを実行しました - 結果をUPDATEに投稿します。 – Dave

+0

@Zoredache - 申し訳ありません - 読みやすくするためにフォーマットするのに少し時間がかかりました。 – Dave

答えて

0

アップロードテーブルにはインデックスがありませんでした。単にそれにインデックスを追加するだけで、それは信じられないほど速くなりました(75000 + msの代わりに142ms)。

私はこの問題をEXPLAIN SELECT ...(@ Zoredacheに感謝します) - 答えの "UPDATE"のEXPLAINの詳細を見つけました。

0

、試してみて、あなたの最初のもの利用をしながら、あなたのWHERE句で使用されているものを利用する加入の一部を動き回りますあなたの順序を不当にMySQLが最適化されていないことを確認するためにSTRAIGHT_JOIN

SELECT STRAIGHT_JOIN 
`Event`.*, `Venue`.`id`, `Venue`.`slug`, `Venue`.`name`, `Venue`.`GPS_Lon`, 
`Venue`.`GPS_Lat`, `Venue`.`city_id`, `VenueCity`.`name`, `VenueCity`.`slug`, 
`Restaurant`.`id`, `Restaurant`.`slug`, `Restaurant`.`name`, `Restaurant`.`GPS_Lat`, 
`Restaurant`.`GPS_Lon`, `Restaurant`.`city_id`, `RestaurantCity`.`name`, 
`RestaurantCity`.`slug`, GROUP_CONCAT(Date.start, "|", Date.end ORDER BY Date.start ASC SEPARATOR "||") AS EventDates 

FROM `events` AS `Event` 
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`) 
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`) 
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) 
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`) 
LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`) 
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`) 
LEFT JOIN uploads AS `Upload` ON (`Upload`.`event_id` = `Event`.`id`) 
WHERE `Event`.`approval_status_id` = 1 
AND `Date`.`start` >= '2011-07-11 12:38:54' 
GROUP BY `Event`.`id` 
ORDER BY `Date`.`start` ASC 
LIMIT 10 

あなたはまた、GROUP_CONCAT声明とは対照的に、それは、これは一時テーブルを作成することができ可能ですと、それはより速くちょうど日付の別のクエリを実行するために見つけるかもしれない(これはあなたのEXPLAINステートメントで明らかになります)。

+0

ありがとう、ありがとう。意識的な注文は何の違いもありませんでした - 今私は知っています! :) – Dave

0

そのgroup_concatを削除してください。テンポラリ・テーブルとファイル・ソートの両方を使用しているという事実は記号です。

また、あなたの外部キー、restaurant_id、venue_idなどにインデックスを付ける必要があります。これらはそれぞれローカルIDを含む必要があります。RestaurantCitycity_id and id`です。

+0

ありがとう、レイ - 私はGROUP_CONCATを削除する可能性について検討します。しかし、それは別の問題に対する私の長い戦いの解決策でしたが、落とすのは難しいかもしれません。 – Dave

2
SELECT STRAIGHT_JOIN 
`Event`.*, `Venue`.`id`, `Venue`.`slug`, `Venue`.`name`, `Venue`.`GPS_Lon`, 
`Venue`.`GPS_Lat`, `Venue`.`city_id`, `VenueCity`.`name`, `VenueCity`.`slug`, 
`Restaurant`.`id`, `Restaurant`.`slug`, `Restaurant`.`name`, `Restaurant`.`GPS_Lat`, 
`Restaurant`.`GPS_Lon`, `Restaurant`.`city_id`, `RestaurantCity`.`name`, 
`RestaurantCity`.`slug`, GROUP_CONCAT(Date.start, "|", Date.end ORDER BY Date.start ASC SEPARATOR "||") AS EventDates 

FROM `events` AS `Event` 
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`) 
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`) 
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) 
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`) 
LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`) 
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`) 
LEFT JOIN uploads AS `Upload` ON (`Upload`.`event_id` = `Event`.`id`) 
WHERE `Event`.`approval_status_id` = 1 
AND `Date`.`start` >= '2011-07-11 12:38:54' 
GROUP BY `Event`.`id` 
ORDER BY `Date`.`start` ASC 
LIMIT 10 
+1

-1ゼロの説明。 –

関連する問題