MYSQL为每个唯一事件选择最早的日期记录

时间:2013-02-27 19:42:53

标签: mysql database optimization

我有以下两个表

CREATE TABLE IF NOT EXISTS `events` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM;

CREATE TABLE IF NOT EXISTS `events_dates` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `event_id` bigint(20) NOT NULL,
  `date` date NOT NULL,
  `start_time` time NOT NULL,
  `end_time` time NOT NULL,
  PRIMARY KEY (`id`),
  KEY `event_id` (`event_id`),
  KEY `date` (`event_id`)
) ENGINE=MyISAM;

链接是event_id的地方

我想要的是检索所有唯一的事件记录及其各自的事件日期,这些事件日期按特定时间段内递增的最小日期排序

基本上,以下查询完全符合我的要求

SELECT Event.id, Event.title, EventDate.date, EventDate.start_time, EventDate.end_time
FROM
    events AS Event
        JOIN
    com_events_dates AS EventDate 
    ON (Event.id = EventDate.event_id AND EventDate.date = (
        SELECT MIN(MinEventDate.date) FROM events_dates AS MinEventDate
        WHERE MinEventDate.event_id = Event.id AND MinEventDate.date >= CURDATE() # AND `MinEventDate`.`date` < '2013-02-27'
        )
    )
WHERE
    EventDate.date >= CURDATE() # AND `EventDate`.`date` < '2013-02-27'
ORDER BY EventDate.date ASC , EventDate.start_time ASC , EventDate.end_time DESC
LIMIT 20

当我想使用group by和其他子查询时,此查询是多次尝试进一步改善最初的慢速时间(1.5秒)的结果。它是最快的但是考虑到总共有1400个事件记录和10000个事件记录,查询需要400多毫秒的时间来处理,我也会根据这个(为了寻呼目的)运行计数,这需要花费大量的时间。好。 奇怪的是,在main where子句中省略了EventDate条件会导致它更高1s +。

我可以采取哪些措施来改善这种情况或在表格结构中使用不同的方法吗?

2 个答案:

答案 0 :(得分:0)

如果您正在讨论优化,那么在可能的情况下包含执行计划会很有帮助。

顺便试试这个(如果你还没试过的话):

SELECT 
  Event.id, 
  Event.title, 
  EventDate.date, 
  EventDate.start_time, 
  EventDate.end_time
FROM
    (select e.id, e.title, min(date) as MinDate
        from events_dates as ed
          join events as e on e.id = ed.event_id
        where date >= CURDATE() and date < '2013-02-27'
        group by e.id, e.title) as Event
  JOIN events_dates AS EventDate ON Event.id = EventDate.event_id 
    and Event.MinDate = EventDate.date
ORDER BY EventDate.date ASC , EventDate.start_time ASC , EventDate.end_time DESC
LIMIT 20
;

#assuming event_dates.date for greater event_dates.id always greater

SELECT 
  Event.id, 
  Event.title, 
  EventDate.date, 
  EventDate.start_time, 
  EventDate.end_time
FROM
    (select e.id, e.title, min(ed.id) as MinID
        from events_dates as ed
          join events as e on e.id = ed.event_id
        where date >= CURDATE() and date < '2013-02-27'
        group by e.id, e.title) as Event
  JOIN events_dates AS EventDate ON Event.id = EventDate.event_id 
    and Event.MinID = EventDate.id
ORDER BY EventDate.date ASC , EventDate.start_time ASC , EventDate.end_time DESC
LIMIT 20

答案 1 :(得分:0)

只是向其他人澄清...... MySQL中的“#”充当延续评论,在查询中基本上被忽略,它不是“AND EventDate.Date&lt;'2013-02-27'” 。也就是说,您似乎想要一个尚未发生的所有事件的列表。我将从一个简单的“预查询”开始,它只是根据尚未发生的事件日期来抓取所有事件和最小日期。然后将该结果连接到其他表以获取您想要的其余字段

SELECT
      E.ID,
      E.Title,
      ED2.`date`,
      ED2.Start_Time,
      ED2.End_Time
   FROM
      ( SELECT
              ED.Event_ID,
              MIN( ED.`date` ) as MinEventDate
           from 
              Event_Dates ED
           where
              ED.`date` >= curdate()
           group by
              ED.Event_ID ) PreQuery
      JOIN Events E
         ON PreQuery.Event_ID = E.ID
      JOIN Event_Dates ED2
         ON PreQuery.Event_ID = ED2.Event_ID
         AND PreQuery.MinEventDate = ED2.`date`
   ORDER BY
      ED2.`date`,
      ED2.Start_Time,
      ED2.End_Time DESC
   LIMIT 20

您的表在事件ID上有多余的索引,只是名称不同。调用索引date的名称并不意味着要被索引的列。 parens(event_id)中的值是构建索引的值。

所以,我会将你的创建表改为......

KEY `date` ( `event_id`, `date`, `start_time` )

或者,手动创建索引。

Create index ByEventAndDate on Event_Dates ( `event_id`, `date`, `start_time` )