日历数据库上的MySQL查询性能

时间:2009-07-11 17:25:43

标签: mysql performance database-design

我正在创建一个日历webapp,我在事件表的创建和后续查询中遇到了性能与存储问题。这个概念是“如何制作一个包含重复事件的表格(每日/每周)?”这是我目前的解决方案:

CREATE TABLE `events` (
  `eventid` int(10) NOT NULL AUTO_INCREMENT,    //primary key
  `evttitle` varchar(255) NOT NULL,             //title of event
  `createdby` char(8) NOT NULL,                 //user identification (I'm using
  `evtdatestart` date NOT NULL,                 ////another's login system)
  `evtdateend` date NOT NULL,
  `evttimestart` time NOT NULL,
  `evttimeend` time NOT NULL,
  `evtrepdaily` tinyint(1) NOT NULL DEFAULT 0,   //if both are '0' then its
  `evtrepweekly` tinyint(1) NOT NULL DEFAULT 0,  //a one time event
  `evtrepsun` tinyint(1) NOT NULL DEFAULT 0,
  `evtrepmon` tinyint(1) NOT NULL DEFAULT 0,
  `evtreptue` tinyint(1) NOT NULL DEFAULT 0,
  `evtrepwed` tinyint(1) NOT NULL DEFAULT 0,
  `evtrepthu` tinyint(1) NOT NULL DEFAULT 0,
  `evtrepfri` tinyint(1) NOT NULL DEFAULT 0,
  `evtrepsat` tinyint(1) NOT NULL DEFAULT 0,
  PRIMARY KEY (`eventid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我还有一个非常小的数字表,从0到62可用于许多不同的事情,但在查询事件的查询中,它通过MOD(num,7)用作星期几。这是查询:

SELECT date, evttitle, evttimestart, evttimeend
FROM (                  //create result of all days between the span of two dates
  SELECT DATE_ADD(startdate, INTERVAL (num-startday) DAY) AS date,
    IF(MOD(num,7)=0,7,MOD(num,7)) AS weekday                      //1=sun...7=sat
  FROM (
    SELECT '@startdate' AS startdate, DAYOFWEEK('@startdate') AS startday,
      '@enddate' AS enddate, DATEDIFF('@enddate','@startdate') AS diff
  ) AS span, numbers                                            //numbers is 0-62
  WHERE num>=startday AND num<=startday+diff
) AS daysinspan, events
WHERE evtdatestart<=date AND evtdateend>=date AND (
  (evtdatestart=evtdateend) OR     //single event
  (evtrepdaily) OR                 //daily event
  (evtrepweekly AND (              //weekly event
    (weekday=1 AND evtrepsun) OR   ////on Sunday
    (weekday=2 AND evtrepmon) OR   ////on Monday
    (weekday=3 AND evtreptue) OR   ////on Tuesday
    (weekday=3 AND evtrepwed) OR   ////on Wednesday
    (weekday=3 AND evtrepthu) OR   ////on Thursday
    (weekday=3 AND evtrepfri) OR   ////on Friday
    (weekday=3 AND evtrepsat)      ////on Saturday
  ))       //end of repeat truths
)
ORDER BY date, evtstarttime;

我喜欢这种方式主要是因为它是一种生成结果的纯SQL方式,它使我不必为重复事件复制事件50次以上,并且它使修改重复事件变得更容易。但是,性能变慢是不可接受的,因为这可能是用户执行的最常见的查询。

另一种方法是不包括evtrep列,只需重新创建一个新的,略有不同的事件,因为跨度需要很多次。但我不喜欢这个想法,因为复制那么多数据的想法让我感到畏缩。但是,如果它能够显着提高我的结果(并且显然查找查询会更容易和更快),那么我想它可以证明额外的存储空间。

你们都认为哪个是更好的计划?或者还有另一个我没想过/提到的吗?

提前致谢!

更新1: person-b提出了一个很好的建议。我相信人b表明我的表可能不是第一正常形式,假设很多(超过30%)的事件是非重复的(在我的情况下,80%以上),这可能是真的。事件可能会重复事件)。但是,我认为我的问题需要重新调整,因为在他的第一次更新中,person-b的建议更改或添加reptimes只会将日期处理推迟到后端(在我的情况下是PHP) ),我的处理时间仍然需要考虑。但我的主要关注点(问题)是:在每个查询的平均值上,最快的方法是计算每个事件的日期和时间,而无需为重复事件手动创建x条目数?

1 个答案:

答案 0 :(得分:1)

尝试规范化表格 - 您可以将事件信息与(多个)日期和重复信息分开。

更新:这是一个例子:
表1:

CREATE TABLE `events` (
  `eventid` int(10) NOT NULL AUTO_INCREMENT,    //primary key
  `repeatid` int(10) NOT NULL,
  `evttitle` varchar(255) NOT NULL,             //title of event
  `createdby` char(8) NOT NULL,                 //user identification (I'm using
  `evtdatestart` date NOT NULL,                 ////another's login system)
  `evtdateend` date NOT NULL,
  `evttimestart` time NOT NULL,
  `evttimeend` time NOT NULL,
  PRIMARY KEY (`eventid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

表2:

CREATE TABLE `repeats` (
  `repweek` tinyint(1) NOT NULL DEFAULT 0, // if 0, don't repeat, otherwise, the day 1..7 of the week
  `repday` tinyint(1) NOT NULL DEFAULT 0,   // repeat daily if 1
  `reptimes` int(10) NOT NULL DEFAULT 0, // 0 for indefinite, otherwise number of times
)

然后,使用这样的查询(未经测试):

SELECT e.evttitle, r.reptimes FROM events e, repeats r WHERE e.eventid = 9

Simple joinsNormalisation上的更多信息(均来自同一指南)。

这将使您的系统更加灵活,并且希望更快。