优化类似的 MySQL 子查询
Posted
技术标签:
【中文标题】优化类似的 MySQL 子查询【英文标题】:Optimizing similar MySQL subqueries 【发布时间】:2012-11-14 00:23:13 【问题描述】:这是我在较大 SQL 脚本中的子查询。它在多个不同的 CASE 语句中执行相同的操作,所以我希望我可以以某种方式组合操作,这样它就不必一遍又一遍地做同样的事情。但是,如果我将 ORDER BY 命令移到 CASE 语句之外,我将无法获得正确的结果。
我将在 JDAY 加入 2 个表,met_data 和 flexgridlayers_table。 Flexgridlayers_table 有 JDAY 和 Segment 的字段,met_data 有 JDAY、TAIR 和 TDEW 的字段(在这个简单的例子中,但实际上有更多的字段)。我通过 Matlab 运行它,所以 variable1 和 variable2 是由嵌套循环设置的值。我需要使用 CASE 语句来说明 variable1 不等于 1 的情况,然后我想输出 0。否则,我想找到与 JDAY 连接对应的值,但这些值可能在 F.JDAY 和 M.JDAY 中不完全匹配。我想匹配最接近的
输出是一个包含字段 JDAY(来自 F.JDAY)、TAIR 和 TDEW 的表。每当我尝试将 ORDER BY 部分移到 CASE 语句之外以摆脱重复的子查询时,我只会得到代表最大 JDAY 的单行结果。这个查询给了我正确的结果 - 有没有办法优化它?
SELECT F.JDAY,
CASE
WHEN *variable1*<>1 THEN 0
ELSE
(SELECT M.TAIR
FROM met_data AS M
WHERE M.Year=2000 AND M.JDAY<=F.JDAY
ORDER BY M.JDAY DESC LIMIT 1)
END AS TAIR,
CASE
WHEN *variable1*<>1 THEN 0
ELSE
(SELECT M.TDEW
FROM met_data AS M
WHERE M.Year=2000 AND M.JDAY<=F.JDAY
ORDER BY M.JDAY DESC LIMIT 1)
END AS TDEW
FROM FlexGridLayers_table AS F
WHERE F.SEGMENT=*variable2*
进一步说明:
此查询从 flexgridlayers_table 中提取所有 JDAY 值,然后在表 met_data 中搜索以查找与该表中最接近的
flexgridlayers_table:
Segment JDAY
2 1.5
2 2.5
2 3.5
3 1.5
3 2.5
3 3.5
met_data:
JDAY Year TAIR TDEW
1.0 2000 7 8
1.1 2000 9 10
1.6 2000 11 12
2.5 2000 13 14
2.6 2000 15 16
3.4 2000 17 18
4.0 2000 19 20
对于 variable1=1 和 variable2=2,我想要的(以及上面的查询返回的)是这样的:
JDAY TAIR TDEW
1.5 9 10
2.5 13 14
3.5 17 18
我只是想知道是否有更有效的方法来编写此查询,因此我不会对每个 TAIR、TDEW 等字段的同一 JDAY 值列表一遍又一遍地执行 ORDER BY 命令。
【问题讨论】:
***.com/questions/12925140/… 这个查询需要 32 秒,有 5 个子查询和 *variable1*=1。我不知道还能从您的链接中获得什么... 请发布此查询的解释。 其实,你能不能把整个查询贴出来,多展示一下var1和var2的上下文是基于哪里的...循环,只是彼此递增,什么... 整个查询大约有 400 行长……这只是一小部分。我正在遍历一个网格(想想 X 和 Y 坐标)...variable1 可以被认为是 Y,variable2 可以被认为是 X。这两个循环的嵌套循环通过连续整数循环,到达每个网格点,起点和终点由用户根据系统的几何形状设置。 【参考方案1】:然后我会写如下......看起来你正在寻找每个 JDAY 的“TAIR”和“TDEW”。如果是这种情况,请在年份条件和 F 与 M JDay 值上将 LEFT JOIN 应用于您的met_data 表。现在通常,这将在每个“JDay”返回多行
SELECT
PQ.JDay,
PQ.MaxJDayPerFDay,
CASE WHEN *var1* <> 1 THEN 0 ELSE M2.TAIR END TAIR,
CASE WEHN *var1* <> 1 THEN 0 ELSE M2.TDEW END TDEW
from
( SELECT
F.JDay,
MAX( M.JDAY ) as MaxJDayPerFDay
from
FlexGridLayers_Table F
JOIN met_Data M
ON M.Year = 2000
AND F.JDay >= M.JDay
where
F.Segment = *var2*
group by
F.JDay ) PQ
JOIN Met_Data M2
on M2.Year = 2000
AND PQ.MaxJDayPerFDay = M2.JDay
现在,它通过在met_data ONCE 中应用MAX() JDay 并按JDay 分组来执行预查询,因此它总是会在每个F.JDay 返回一条记录。因此,现在您有一个预限定为您的 F.Segment = 变量 2 的查询。如果您想要从“F”表中获得其他列,请根据需要将它们放入此“PreQuery”(PQ 别名)中。
然后,这个结果可以立即连接回met_data 表,因为现在可以从预查询中明确知道一天的值。因此,您现在可以一次获取 TAIR 和 TDEW 值,而不是针对每条记录应用两个单独的查询。
希望这有意义,如果没有,请告诉我。
【讨论】:
效果很好!计算时间从 32 秒缩短到 2 秒……还不错!我什至没有想过使用 group by...以上是关于优化类似的 MySQL 子查询的主要内容,如果未能解决你的问题,请参考以下文章