Sql Oracle查询优化建议
下面的查询需要很长时间,下面的谓词只用于获取唯一的记录,因此我想知道是否有其他方法可以重写同一个查询而不多次调用下面的谓词来获取唯一的IDSql Oracle查询优化建议,sql,oracle,query-optimization,greatest-n-per-group,window-functions,Sql,Oracle,Query Optimization,Greatest N Per Group,Window Functions,下面的查询需要很长时间,下面的谓词只用于获取唯一的记录,因此我想知道是否有其他方法可以重写同一个查询而不多次调用下面的谓词来获取唯一的ID select max(c.id) from plocation c where c.ids = y.ids and c.idc = y.idc) select max(cr.id) from plocation_log cr where cr.ids = yt.ids and cr.idc = yt.idc) select max(pr.id) from p
select max(c.id) from plocation c where c.ids = y.ids and c.idc = y.idc)
select max(cr.id) from plocation_log cr where cr.ids = yt.ids and cr.idc = yt.idc)
select max(pr.id) from patentpr where pr.ids = p.ids and pr.idc = p.idc)
我的完整示例查询
SELECT to_char(p.pid) AS patentid,
p.name,
x.dept,
y.location
FROM patent p
JOIN pdetails x ON p.pid = x.pid AND x.isactive = 1
JOIN plocation y
ON y.idr = p.idr
AND y.idc = p.idc
AND y.id = *(select max(c.id) from plocation c where c.ids = y.ids and c.idc = y.idc)*
AND y.idopstype in (36, 37)
JOIN plocation_log yt
ON yt.idr = y.idr
AND yt.idc= y.idc
AND yt.id = *(select max(cr.id) from plocation_log cr where cr.ids = yt.ids and cr.idc = yt.idc)*
AND yt.idopstype in (36,37)
WHERE
p.idp IN (10,20,30)
AND p.id = *(select max(pr.id) from patent pr where pr.ids = p.ids and pr.idc = p.idc)*
AND p.idopstype in (36,37)
正如Impaler所评论的,一种选择是使用分析函数而不是相关子查询。其思想是使用
rank()
对子查询中的记录进行排序,然后在外部查询中进行筛选(连接条件或WHERE
子句)
考虑:
SELECT to_char(p.pid) AS patentid,
p.name,
x.dept,
y.location
FROM (SELECT p.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM patinet) p
JOIN pdetails x ON p.pid = x.pid AND x.isactive = 1
JOIN (SELECT y.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM plocation y) y
ON y.idr = p.idr
AND y.idc = p.idc
AND y.idopstype in (36, 37)
AND y.rn = 1
JOIN (SELECT y.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM plocation_log yt) yt
ON yt.idr = y.idr
AND yt.idc= y.idc
AND yt.idopstype in (36,37)
AND yt.rn = 1
WHERE
p.idp IN (10,20,30)
AND p.idopstype in (36,37)
AND p.rn = 1
正如Impaler所评论的,一种选择是使用分析函数而不是相关子查询。其思想是使用
rank()
对子查询中的记录进行排序,然后在外部查询中进行筛选(连接条件或WHERE
子句)
考虑:
SELECT to_char(p.pid) AS patentid,
p.name,
x.dept,
y.location
FROM (SELECT p.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM patinet) p
JOIN pdetails x ON p.pid = x.pid AND x.isactive = 1
JOIN (SELECT y.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM plocation y) y
ON y.idr = p.idr
AND y.idc = p.idc
AND y.idopstype in (36, 37)
AND y.rn = 1
JOIN (SELECT y.*, RANK() OVER(PARTITION BY ids, idc ORDER BY id) rn FROM plocation_log yt) yt
ON yt.idr = y.idr
AND yt.idc= y.idc
AND yt.idopstype in (36,37)
AND yt.rn = 1
WHERE
p.idp IN (10,20,30)
AND p.idopstype in (36,37)
AND p.rn = 1
考虑加入聚合CTE,以计算每个组的
MAX
值一次,而不是为每个外部查询行按行计算MAX
。此外,请确保使用信息更丰富的表格别名,而不是a、b、c
或x、y、z
样式
WITH loc_max AS
(select ids, idc, max(id) as max_id from plocation group ids, idc)
, log_max AS
(select ids, idc, max(id) as max_id from plocation_log group by ids, idc)
, pat_max AS
(select ids, idc, max(id) as max_id from patent pr group by ids, idc)
SELECT to_char(pat.pid) AS patentid
, pat.name
, det.dept
, loc.location
FROM patent pat
JOIN pdetails det
ON pat.pid = det.pid
AND det.isactive = 1
JOIN plocation loc
ON loc.idr = pat.idr
AND loc.idc = pat.idc
AND loc.idopstype IN (36, 37)
JOIN loc_max -- ADDED CTE JOIN
ON loc.id = loc_max.max_id
AND loc.ids = loc_max.ids
AND loc.idc = loc_max.idc
JOIN plocation_log log
ON log.idr = log.idr
AND log.idc = log.idc
AND log.idopstype in (36,37)
JOIN log_max -- ADDED CTE JOIN
ON log.id = log_max.max_id
AND log.ids = log_max.ids
AND log.idc = log_max.idc
JOIN pat_max -- ADDED CTE JOIN
ON pat.id = pat_max.max_id
AND pat.ids = pat_max.ids
AND pat.idc = pat_max.idc
WHERE pat.idp IN (10, 20, 30)
AND pat.idopstype IN (36, 37)
考虑加入聚合CTE,以计算每个组的
MAX
值一次,而不是为每个外部查询行按行计算MAX
。此外,请确保使用信息更丰富的表格别名,而不是a、b、c
或x、y、z
样式
WITH loc_max AS
(select ids, idc, max(id) as max_id from plocation group ids, idc)
, log_max AS
(select ids, idc, max(id) as max_id from plocation_log group by ids, idc)
, pat_max AS
(select ids, idc, max(id) as max_id from patent pr group by ids, idc)
SELECT to_char(pat.pid) AS patentid
, pat.name
, det.dept
, loc.location
FROM patent pat
JOIN pdetails det
ON pat.pid = det.pid
AND det.isactive = 1
JOIN plocation loc
ON loc.idr = pat.idr
AND loc.idc = pat.idc
AND loc.idopstype IN (36, 37)
JOIN loc_max -- ADDED CTE JOIN
ON loc.id = loc_max.max_id
AND loc.ids = loc_max.ids
AND loc.idc = loc_max.idc
JOIN plocation_log log
ON log.idr = log.idr
AND log.idc = log.idc
AND log.idopstype in (36,37)
JOIN log_max -- ADDED CTE JOIN
ON log.id = log_max.max_id
AND log.ids = log_max.ids
AND log.idc = log_max.idc
JOIN pat_max -- ADDED CTE JOIN
ON pat.id = pat_max.max_id
AND pat.ids = pat_max.ids
AND pat.idc = pat_max.idc
WHERE pat.idp IN (10, 20, 30)
AND pat.idopstype IN (36, 37)
您能提供关于表定义的详细信息吗?如果您使用窗口函数而不是相关子查询来重新表述查询,它将运行得更快。您的Oracle版本是否支持windows函数(
OVER
子句)?Oracle从8i:)开始支持窗口分析函数。我认为没有人使用旧版本。请向我们展示表上的索引。@谢谢。我喜欢这个建议,对于我的实例,您是否碰巧有一个带有窗口函数而不是相关子查询的示例来获取唯一Id?您能否提供有关表定义的详细信息?如果您使用窗口函数而不是相关子查询来重新表述查询,它将运行得更快。您的Oracle版本是否支持windows函数(OVER
子句)?Oracle从8i:)开始支持窗口分析函数。我认为没有人使用旧版本。请向我们展示表上的索引。@谢谢。我喜欢这个建议,你是否碰巧有一个窗口函数的例子,而不是我的实例的相关子查询,以获得唯一的Id请?我喜欢这种方法。显然,解释计划显示的成本比我之前的查询要高一些。不知道为什么,但实际上你的方法是有意义的。考虑索引<代码>连接< /代码>列。无论解释计划由于CTE和newJOIN
s而显示更多步骤,查询整体运行是否较慢?是。这确实很慢。我已经结束了以另一种方式重写查询的过程,并且看起来很有效。谢谢你的帮助。我喜欢这种方法。显然,解释计划显示的成本比我之前的查询要高一些。不知道为什么,但实际上你的方法是有意义的。考虑索引<代码>连接< /代码>列。无论解释计划由于CTE和newJOIN
s而显示更多步骤,查询整体运行是否较慢?是。这确实很慢。我已经结束了以另一种方式重写查询的过程,并且看起来很有效。谢谢你的帮助。