我正在尝试使用此查询在多个时段之间查找个人的考试结果:
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) )
上一个/下一个/ 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的序列中的第一个。)
对不起打字错误 - 我的键盘坏了,提前谢谢。
答案 0 :(得分:2)
问题在于您将ORed组合在一起的所有条件。
如果可能,重构数据库,以便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表中有任何其他句点,则可以删除WHERE子句的AND T.PeriodType
部分。
答案 1 :(得分: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子句。
编辑 - 增加
如果您不想运行查询,请至少尝试比较估计的执行计划