2010-10-27 34 views
2

我想寫一個查詢來獲得課程信息和預訂和出席者的數量。每門課程可以有很多預訂,每個預訂可以有很多與會者。快速複雜的查詢來選擇預訂

我們已經有一份工作報告,但它使用多個查詢來獲取所需信息。一個獲得課程,一個獲得預訂,一個獲得參加者的人數。這是非常緩慢的,因爲數據庫的規模已經擴大到了。

有對報告的一些額外的條件:

  • 預訂必須超過5 分鐘前發,或已被確認
  • 預訂不得取消
  • 課程不得標記爲已刪除
  • 課程場地和地點必須爲LIKE搜索字符串
  • 無預訂課程必須出現在結果

這是表結構:(我省略了不必要的信息。所有字段不爲空且沒有默認值)

mysql> DESCRIBE first_aid_courses;

+------------------+--------------+-----+----------------+ 
| Field   | Type   | Key | Extra   | 
+------------------+--------------+-----+----------------+ 
| id    | int(11)  | PRI | auto_increment | 
| course_date  | date   |  |    | 
| region_id  | int(11)  |  |    | 
| location   | varchar(255) |  |    | 
| venue   | varchar(255) |  |    | 
| number_of_spaces | int(11)  |  |    | 
| deleted   | tinyint(1) |  |    | 
+------------------+--------------+-----+----------------+ 

mysql> DESCRIBE first_aid_bookings;

+-----------------------+--------------+-----+----------------+ 
| Field     | Type   | Key | Extra   | 
+-----------------------+--------------+-----+----------------+ 
| id     | int(11)  | PRI | auto_increment | 
| first_aid_course_id | int(11)  |  |    | 
| placed    | datetime  |  |    | 
| confirmed    | tinyint(1) |  |    | 
| cancelled    | tinyint(1) |  |    | 
+-----------------------+--------------+-----+----------------+ 

mysql> DESCRIBE first_aid_attendees;

+----------------------+--------------+-----+----------------+ 
| Field    | Type   | Key | Extra   | 
+----------------------+--------------+-----+----------------+ 
| id     | int(11)  | PRI | auto_increment | 
| first_aid_booking_id | int(11)  |  |    | 
+----------------------+--------------+-----+----------------+ 

mysql> DESCRIBE regions;

+----------+--------------+-----+----------------+ 
| Field | Type   | Key | Extra   | 
+----------+--------------+-----+----------------+ 
| id  | int(11)  | PRI | auto_increment | 
| name  | varchar(255) |  |    | 
+----------+--------------+-----+----------------+ 

,我需要選擇以下:

Course ID:  first_aid_courses.id 
Date:    first_aid_courses.course_date 
Region   regions.name 
Location:   first_aid_courses.location 
Bookings:   COUNT(first_aid_bookings) 
Attendees:  COUNT(first_aid_attendees) 
Spaces Remaining: COUNT(first_aid_bookings) - COUNT(first_aid_attendees) 

這是我到目前爲止有:

SELECT `first_aid_courses`.*, 
     COUNT(`first_aid_bookings`.`id`) AS `bookings`, 
     COUNT(`first_aid_attendees`.`id`) AS `attendees` 
FROM `first_aid_courses` 
     LEFT JOIN `first_aid_bookings` 
     ON `first_aid_courses`.`id` = 
      `first_aid_bookings`.`first_aid_course_id` 
     LEFT JOIN `first_aid_attendees` 
     ON `first_aid_bookings`.`id` = 
      `first_aid_attendees`.`first_aid_booking_id` 
WHERE (`first_aid_courses`.`location` LIKE '%$search_string%' 
      OR `first_aid_courses`.`venue` LIKE '%$search_string%') 
     AND `first_aid_courses`.`deleted` = 0 
     AND (`first_aid_bookings`.`placed` > '$five_minutes_ago' 
      AND `first_aid_bookings`.`cancelled` = 0 
       OR `first_aid_bookings`.`confirmed` = 1) 
GROUP BY `first_aid_courses`.`id` 
ORDER BY `course_date` DESC 

它不是相當的工作,任何一個可以幫我寫正確的查詢?同樣在這個數據庫中有1000行,所以任何幫助使它快速被讚賞(像索引哪些字段)。

+0

它是如何「不太工作」? – 2010-10-27 21:59:41

+0

預訂數量/出席者數量錯誤 – Petah 2010-10-27 22:05:39

回答

2

好吧,我回答了我自己的問題。有時候,有人會問你一個問題來找出答案。

SELECT `first_aid_courses`.*, 
     `regions`.`name`       AS `region_name`, 
     COUNT(DISTINCT `first_aid_bookings`.`id`) AS `bookings`, 
     COUNT(`first_aid_attendees`.`id`)   AS `attendees` 
FROM `first_aid_courses` 
     JOIN `regions` 
     ON `first_aid_courses`.`region_id` = `regions`.`id` 
     LEFT JOIN `first_aid_bookings` 
     ON `first_aid_courses`.`id` = 
      `first_aid_bookings`.`first_aid_course_id` 
     LEFT JOIN `first_aid_attendees` 
     ON `first_aid_bookings`.`id` = 
      `first_aid_attendees`.`first_aid_booking_id` 
WHERE (`first_aid_courses`.`location` LIKE '%$search_string%' 
      OR `first_aid_courses`.`venue` LIKE '%$search_string%') 
     AND `first_aid_courses`.`deleted` = 0 
     AND (`first_aid_bookings`.`cancelled` = 0 
      AND `first_aid_bookings`.`confirmed` = 1) 
GROUP BY `first_aid_courses`.`id` 
ORDER BY `course_date` ASC 
1

這是完全未經測試,但也許嘗試選擇非空行擔保和與會者的計數,像這樣:

SUM(IF(`first_aid_bookings`.`id` IS NOT NULL, 1, 0)) AS `bookings`, 
COUNT(IF(`first_aid_attendees`.`id` IS NOT NULL, 1, 0)) AS `attendees` 
+0

我無法使用該功能。它返回與我的查詢相同的結果。 – Petah 2010-10-27 23:01:54

1

除非你有,但只是沒有表現出來,好好看看對於索引,如果沒有它們,那麼在任何引用除主鍵之外的任何查詢的性能上,您都會失去一個數量級。

另一個主要表現是LIKE'%nnn%'。

對這些可以做些什麼嗎?

但有了一些好的索引,這個查詢應該沒問題,如果你有硬件來備份它。

我有查詢做像數百萬行的表。如果查詢的其餘部分可以消除任何不必要的匹配,那麼這不成問題。

你可以去子查詢來減少LIKE查詢的範圍。

+0

是的,我在很多領域(包括'LIKE'語句中使用的2個字段)的索引,我不是100%確定他們在正確的領域。除非用戶鍵入搜索查詢,否則'LIKE'語句被省略。 – Petah 2010-10-27 22:36:02

+0

查看EXPLAIN命令讓sql引擎自己分析查詢 - 它會告訴你(以一種有點神祕的方式)是否有任何缺失的索引 – 2010-10-28 16:10:05