Mysql 快速复杂查询以选择预订

Mysql 快速复杂查询以选择预订,mysql,optimization,query-optimization,Mysql,Optimization,Query Optimization,我正在尝试编写一个查询,以获取课程信息以及预订和与会者的数量。每门课程可以有多个预订,并且每个预订可以有多个参与者 我们已经有了一个工作报告,但它使用多个查询来获取所需的信息。一个用于获取课程,一个用于获取预订,另一个用于获取出席人数。这是非常缓慢的,因为数据库的大小已经增长到 报告有许多附加条件: 预订次数必须超过5次 几分钟前,还是已经确认了 预订不能取消 不得将课程标记为已删除 课程地点和地点必须像搜索字符串一样 结果中必须显示未预订的课程 这是表结构:(我省略了不需要的信息。所有字段

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

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

报告有许多附加条件:

  • 预订次数必须超过5次 几分钟前,还是已经确认了
  • 预订不能取消
  • 不得将课程标记为已删除
  • 课程地点和地点必须像搜索字符串一样
  • 结果中必须显示未预订的课程
这是表结构:(我省略了不需要的信息。所有字段都不是空的,没有默认值)

mysql>描述急救课程

+------------------+--------------+-----+----------------+
| 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>描述急救预约

+-----------------------+--------------+-----+----------------+
| 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>描述急救参与者

+----------------------+--------------+-----+----------------+
| Field                | Type         | Key | Extra          |
+----------------------+--------------+-----+----------------+
| id                   | int(11)      | PRI | auto_increment |
| first_aid_booking_id | int(11)      |     |                |
+----------------------+--------------+-----+----------------+
mysql>描述区域

+----------+--------------+-----+----------------+
| 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行,因此任何帮助都将非常感谢(如索引哪些字段)

这完全未经测试,但可以尝试为预订和与会者选择非空行计数,如下所示:

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`

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

另一个主要的性能影响是“%nnn%”

有可能用这些做点什么吗

但是有了一些好的索引,如果您有硬件来备份的话,这个查询应该很好

我在有数百万行的表上有类似的查询。如果查询的其余部分可以消除任何不必要的匹配,这就不是问题


您可以使用子查询来缩小类似查询的范围

好的,我回答了我自己的问题。有时候,问一个问题来找出答案会有帮助

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  

怎么会“不太有效”?预订/与会者的数量是错误的。是的,我在很多字段上都有索引(包括
LIKE
语句中使用的两个字段),但我不能100%确定它们在正确的字段上。此外,除非用户在搜索查询中键入内容,否则将省略
LIKE
语句。请查找EXPLAIN命令,让sql引擎本身分析查询——它将告诉您(以某种隐晦的方式)是否有任何缺少的索引,我无法使其工作。它返回与my查询相同的结果。