1

次の2つのテーブルがあります

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 条件を省略すると、これはさらに 1 秒以上高くなります。

これを改善するためにできること、またはテーブル構造での別のアプローチはありますか?

4

2 に答える 2

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
于 2013-02-28T01:34:32.047 に答える
0

他の人に明確にするために... MySQLの「#」は継続コメントとして機能し、クエリでは基本的に無視されます。「AND 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 に冗長なインデックスがあります。インデックスの名前を呼んでも、dateその列がインデックスされているわけではありません。括弧 ( ) 内の値event_idは、インデックスが構築されているものです。

だから、私はあなたの作成テーブルを次のように変更します...

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

または、インデックスを手動で作成します。

Create index ByEventAndDate on Event_Dates ( `event_id`, `date`, `start_time` )
于 2013-02-28T03:37:26.740 に答える