【问题标题】:MYSQL Selecting oldest date record for each unique eventMYSQL 为每个唯一事件选择最旧的日期记录
【发布时间】:2013-02-28 19:55:45
【问题描述】:

我有以下两张表

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 多毫秒的时间来处理,我也基于此运行计数(用于分页目的),这需要大量时间出色地。 奇怪的是,在主 where 子句中省略 EventDate 条件会导致它甚至更高 1s+。

我可以做些什么来改进这个或表结构的不同方法?

【问题讨论】:

  • 没有order by子句的情况如何?
  • 如果没有订单,它的执行速度会快很多,但我真的需要这样排序。

标签: mysql database optimization


【解决方案1】:

只是为了向其他人澄清...... MySQL 中的“#”充当延续注释,在查询中基本上被忽略,它不是“AND EventDate.Date

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

【讨论】:

  • 我已经以这种方式对其进行了调整,它的运行速度肯定是原来的两倍多。但是预查询需要按 Event_ID 分组,否则它只选择了我所有事件中最低的日期
  • @zakel,很高兴它起作用了,我修改了答案中的“分组依据”......抱歉我错过了,但很高兴你很容易识别它。
【解决方案2】:

如果您谈论的是优化,尽可能包含执行计划会很有帮助。

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

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

【讨论】:

  • 您的第一个解决方案与 DRapp 的解决方案非常相似。不幸的是,第二个是行不通的,因为对于更高的 id,日期可能会更小。
猜你喜欢
  • 2012-06-04
  • 1970-01-01
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
相关资源
最近更新 更多