如何在oracle中优化此sql?
我有一个查询操作,如下所示,它来自单个表,但子查询太多。有人能帮上忙吗如何在oracle中优化此sql?,sql,oracle,Sql,Oracle,我有一个查询操作,如下所示,它来自单个表,但子查询太多。有人能帮上忙吗 SELECT t.order_no , user_assign , t.busi_code , t.inst_addr4 AS district, t.inst_addr3 AS estate ,listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by da
SELECT t.order_no ,
user_assign ,
t.busi_code ,
t.inst_addr4 AS district,
t.inst_addr3 AS estate
,listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by date_appoint asc) as "日期排序"
FROM mtce_detail t
WHERE order_no IN
(SELECT order_no
FROM
(SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE order_no IN
(SELECT order_no
FROM mtce_detail
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
)
AND date_appoint <= to_date('2014-04-17', 'yyyy-mm-dd')
GROUP BY order_no,
user_assign
)
WHERE total > 2
)
group by t.order_no,t.user_assign,t.busi_code,t.inst_addr4,t.inst_addr3
将t.order_no IN处替换为
仅就这一部分更换电话和日期:
SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE order_no IN
(SELECT order_no
FROM mtce_detail
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
)
你为什么不这样写呢:
SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE order_no IN
( SELECT order_no
FROM mtce_detail
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
)
AND date_appoint <= to_date('2014-04-17', 'yyyy-mm-dd')
GROUP BY order_no
, user_assign
having count(order_no) > 2
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group (order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE date_appoint <= date '2014-04-17'
GROUP BY order_no
, user_assign
having count(order_no) > 2
and count(case date_appoint when date '2014-04-17' then 1 end) >= 1
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
如果要进行多个内部选择,则必须避免此情况,请改用此选项:
SELECT t.order_no ,
user_assign ,
t.busi_code ,
t.inst_addr4 AS district,
t.inst_addr3 AS estate
,listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by date_appoint asc) as "日期排序"
FROM mtce_detail t
WHERE exists
(SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE date_appoint <= to_date('2014-04-17', 'yyyy-mm-dd')
AND m.order_no = t.order_no
GROUP BY order_no, user_assign
HAVING count(order_no) > 2
)
group by t.order_no,t.user_assign,t.busi_code,t.inst_addr4,t.inst_addr3
您可以采取的第一步是删除total>2的子查询,并将其替换为更优雅的HAVING子句,如下所示:
SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE order_no IN
( SELECT order_no
FROM mtce_detail
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
)
AND date_appoint <= to_date('2014-04-17', 'yyyy-mm-dd')
GROUP BY order_no
, user_assign
having count(order_no) > 2
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group (order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE date_appoint <= date '2014-04-17'
GROUP BY order_no
, user_assign
having count(order_no) > 2
and count(case date_appoint when date '2014-04-17' then 1 end) >= 1
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
下一步是通过删除最里面的子查询来消除表访问。只需选择2014年4月17日当天或之前的所有mtce_详细信息,并一次性统计当天和之前发生的事件数。现在,您可以在having子句中使用这些计算出的数字,如下所示:
SELECT m.order_no,
user_assign ,
COUNT(order_no) AS total
FROM mtce_detail m
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group(order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE order_no IN
( SELECT order_no
FROM mtce_detail
WHERE date_appoint = to_date('2014-04-17', 'yyyy-mm-dd')
)
AND date_appoint <= to_date('2014-04-17', 'yyyy-mm-dd')
GROUP BY order_no
, user_assign
having count(order_no) > 2
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
SELECT t.order_no
, user_assign
, t.busi_code
, t.inst_addr4 AS district
, t.inst_addr3 AS estate
, listagg(to_char(date_appoint,'yyyy-mm-dd'),',') within group (order by date_appoint asc) as "something_chinese"
FROM mtce_detail t
WHERE order_no IN
( SELECT m.order_no
FROM mtce_detail m
WHERE date_appoint <= date '2014-04-17'
GROUP BY order_no
, user_assign
having count(order_no) > 2
and count(case date_appoint when date '2014-04-17' then 1 end) >= 1
)
group by t.order_no
, t.user_assign
, t.busi_code
, t.inst_addr4
, t.inst_addr3
性能应该略有提高,但您的查询仍然包含对同一个表的两个表访问。如果需要最后一个表访问,可以将分析函数与partition子句一起使用。您的查询将更难阅读,但速度更快。这是留给读者的一个有趣的练习:-。因为我没有测试数据有什么问题?太慢了?如果是这样,请发布执行计划。优化有时涉及将查询拆分为多个子查询,这些子查询可以并行执行,因此hving子查询本身并不是一件坏事。正如@Thilo所说:问题出在哪里?慢吗?没问题。我只是想知道是否有任何方法可以优化它,并使它更加友好。我觉得这太笨拙了。哦,不。一些订单记录了2014-04-17和其他时间。所以同一订单有多行?是的,我需要获取这些行,即使其指定日期不是2014-04-17,但至少有一行的订单号与之相同。日期在哪里,“yyyy-mm-dd”?这也选择了2014年4月17日没有出现的mcte_详细信息。他从mtce_详细信息中选择了3次,因此有一个条款规定date_-Apprimit@NightFox79语法错误,总数大于2,我认为countorder_no>2更好,谢谢大家:这通常都是胡说八道。证据:不要使用oracle版本8中2001年的文章。这不适用于现在,在10和11中,如果没有使用相同执行计划的数据,SQLFIDLE的性能会更好:与