快速复杂查询以选择预订

时间:2010-10-27 21:56:13

标签: mysql optimization query-optimization

我正在尝试编写查询以获取课程信息以及预订和与会者的数量。每个课程都可以有很多预订,每个预订可以有很多与会者。

我们已经有了一份工作报告,但它使用多个查询来获取所需信息。一个是获得课程,一个是预订,另一个是参加人数。由于数据库的大小已经增长,这非常慢。

报告有许多额外条件:

  • 预订必须超过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区域;

+----------+--------------+-----+----------------+
| 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行,因此可以了解任何有关快速行的帮助(比如要索引的字段)。

3 个答案:

答案 0 :(得分: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 :(得分: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`

答案 2 :(得分:1)

除非您拥有它但只是不显示它,否则请仔细查看索引,如果没有它们,您在任何引用除主键之外的任何查询的性能上都会失去一个数量级。

另一个重要的表现是LIKE'%nnn%'。

是否可以对这些做点什么?

但是有了一些好的索引,如果你有硬件备份它,这个查询应该没问题。

我有对数百万行的表执行LIKE的查询。如果查询的其余部分可以消除任何不必要的匹配,那不是问题。

您可以使用子查询来减少LIKE查询的范围。