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

MYSQL为每个唯一事件选择最早的日期记录,mysql,database,optimization,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,

我有下面两张桌子

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;
其中链接是事件\ u 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毫秒以上的时间来处理,我也基于此运行了一个计数,以便进行分页,这也需要很多时间。 奇怪的是,在主where子句中省略EventDate条件会导致更高的1s+


我能做些什么来改进表结构的这种或不同的方法吗?

如果您谈论的是优化,那么在可能的情况下包括执行计划会很有帮助

顺便说一句,如果您还没有尝试过,请尝试以下方法:

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

只是为了向其他人澄清。。。MySQL中的注释作为延续注释,在查询中基本上被忽略,它不是和EventDate.Date<'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上有冗余索引,只是名称不同而已。调用索引日期的名称并不意味着该列正在被索引。parens event_id中的值是建立索引的基础

所以,我想将您的创建表更改为

KEY `date` ( `event_id`, `date`, `start_time` )
或者,手动创建索引

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

如果没有ORDERBY子句,它的性能如何?如果没有ORDERBY,它的性能会快得多,但我真的需要它们按这种方式排序。我对它进行了这样的调整,它的运行速度肯定是原来的两倍多。但是,预查询需要按事件\u ID分组,否则它只选择所有事件中最低的一个日期events@zakel,很高兴它成功了,我修改了答案中的“分组依据”。。。很抱歉我错过了它,但很高兴您很容易识别它。您的第一个解决方案与DRapp的非常相似。不幸的是,第二种方法行不通,因为对于更高的id,日期可能更小。