2013-02-27 111 views
0

我有以下两个表格MYSQL选择最早的日期记录为每一个独特的事件

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 

此查询是多次尝试进一步改进最初有(1.5秒)我想使用group by和其他子查询时的慢速时间的结果。它是目前最快的一个,但考虑到总共有1400个事件记录和10000个事件记录,查询需要400+毫秒的时间来处理,同时我也运行了一个基于此的计数(用于分页目的),这需要很多时间好。 奇怪的是,忽略了主要where子句中的EventDate条件导致它更高1s +。

有什么我可以做的,以改善这种或在表结构的不同方法?

+0

它如何执行没有order by子句? – 2013-02-27 21:23:54

+0

没有它的顺序执行速度快很多,但我真的需要它们按这种方式排序。 – zakel 2013-02-28 11:36:22

回答

0

只是为了澄清对任何人......“#”号在MySQL作为一个延续评论,基本上在查询中被忽略,它不是“AND EventDate.Date <'2013-02-27'”。这就是说,看起来你想要一个所有尚未发生的事件的列表。我会从一个简单的“prequery”开始,它只是抓住所有事件,并根据尚未发生的事件日期确定最短日期。然后,该结果加入到其他表,以获得其余字段你想

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`) 
+0

我已经用这种方法调整过它,它的运行速度要快两倍以上。 但是,预先查询需要Event_ID所在的组,否则它只会选择所有事件的单个最低日期 – zakel 2013-02-28 11:37:09

+0

@zakel,很高兴它的工作,我在答案中修改了'group by'...对不起,我错过了它,但很高兴你很容易识别它。 – DRapp 2013-02-28 11:56:27

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 
+0

您的第一个解决方案与DRapp的解决方案非常相似。 不幸的是,第二个不会工作,因为对于更高的ID,日期可以更小。 – zakel 2013-02-28 11:42:15

相关问题