0

我正在尝试使用此查询在多个时期之间查找个人的考试结果:

SELECT * FROM RESULTS AS R, Define_Times AS T 
WHERE R.PERSONID = T.PERSONID AND ( 
(R.DATE BETWEEN T.Previous_Month_Start AND T.Previous_Month_End) OR 
(R.DATE BETWEEN T.Next_Month_Start AND T.Next_Month_End) OR 
(R.DATE BETWEEN T.Six_Month_Start AND T.Six_Month_End) OR 
(R.DATE BETWEEN T.One_Year_Start AND T.One_Year_End) OR 
(R.DATE BETWEEN T.Two_Year_Start AND T.Two_Year_End) OR 
(R.DATE BETWEEN T.Three_Year_Start AND T.Three_Year_End) OR 
(R.DATE BETWEEN T.Four_Year_Start AND T.Four_Year_End) )

Previous/Next/One_Year 等因人而异。

解释给出:

| id | select_type | table | type | possible_keys | key  | key_len | ref             | rows  | Extra       |
|  1 | SIMPLE      | T     | ALL  | PEOPLE        | NULL | NULL    | NULL            | 75775 |             |
|  1 | SIMPLE      | R     | ref  | IDX3,IDX2     | IDX3 | 5       | T.PERSONID      |  3550 | Using where |

结果表有大约 3 亿行。Define_Times 有 75,000 个。

它需要AGES。

我看到第一种类型是 ALL,这很糟糕。但如果情况如此糟糕,为什么不使用它认为可能的 PERSONID(称为 PEOPLE)上的索引?我能做些什么来改善这一点?

我也看不到它使用日期索引 - R.DATE 上有一个。(它是 IDX2 索引中 5 序列中的第一个。)

抱歉有任何错别字 - 我的键盘坏了,提前致谢。

4

2 回答 2

2

问题是您将所有条件组合在一起。

如果可能,重组您的数据库,使 Define_Time 只有四列:

 CREATE TABLE Define_Times (
    PersonID INTEGER,
    PeriodType SomeType,
    StartDate DATE,
    EndDate DATE )

然后,每个人获得 7 条记录(或更多,如果您在示例中没有搜索更多期间),其中 PeriodType 指示日期指定的期间(您可以使用 PM、NM、SM、1Y 等文本值, 2Y、3Y、4Y 或者您可以使用指向另一个表中的描述的整数值)。

然后,像这样重写您的查询:

SELECT * FROM RESULTS AS R, Define_Times AS T 
WHERE R.PERSONID = T.PERSONID 
   AND R.DATE BETWEEN T.StartDate AND T.EndDate
   AND T.PeriodType IN (PM,NM,SM,1Y,2Y,3Y,4Y)

这个查询至少是可优化的。

此查询将为每个人在每个匹配期间生成一条记录。如果您的期间不重叠,那很好(只会有一个匹配的记录)。如果您的期间确实重叠并且您只希望每个结果集有一条记录,则需要通过聚合结果集中的记录来使用 DISTINCT 或 GROUP BY 做一些额外的工作。

另外,请注意,如果您在 Define_Times 表中没有AND T.PeriodType任何额外的句点,那么您可以删除WHERE 子句的一部分。

于 2013-09-25T16:11:58.897 回答
0

作为比较,你能运行这个等效的查询吗

SELECT * FROM Define_Times AS T 
INNER JOIN RESULTS AS R on
(R.PERSONID = T.PERSONID and 
  ( 
  (R.DATE BETWEEN T.Previous_Month_Start AND T.Previous_Month_End) OR 
  (R.DATE BETWEEN T.Next_Month_Start AND T.Next_Month_End) OR 
  (R.DATE BETWEEN T.Six_Month_Start AND T.Six_Month_End) OR 
  (R.DATE BETWEEN T.One_Year_Start AND T.One_Year_End) OR 
  (R.DATE BETWEEN T.Two_Year_Start AND T.Two_Year_End) OR 
  (R.DATE BETWEEN T.Three_Year_Start AND T.Three_Year_End) OR 
  (R.DATE BETWEEN T.Four_Year_Start AND T.Four_Year_End) 
  ) 
)

我已经看到优化器有时以这种形式工作得更好。

此外,由于您对表达式之间的所有日期进行 OR,因此几乎无法使用日期索引,因为任何日期范围都可以满足 where 子句。

编辑——添加

如果您不想运行查询,至少尝试比较估计的执行计划

于 2013-09-25T15:36:09.570 回答