oracle sql查询进一步优化1

Posted

技术标签:

【中文标题】oracle sql查询进一步优化1【英文标题】:oracle sql query optimization further 1 【发布时间】:2016-11-16 09:37:39 【问题描述】:

我已经编写了一个查询来从 bdb 中选择 * 以仅获取最新 ACT 中 DAY、INST 组合的 PRICE 中的更新值 我创建了一个像

的表
CREATE TABLE bdb(
   ACT  NUMBER(8) NOT NULL,
   INST NUMBER(8) NOT NULL,
   DAY  DATE      NOT NULL,
   PRICE  VARCHAR2 (3),
   CURR   NUMBER (8,2),
   PRIMARY KEY (ACT,INST,DAY)
);

用它来填充表格

DECLARE
   t_day  bdb.day%type:= '1-JAN-16';
   n pls_integer;
BEGIN


<< act_loop >>
FOR i IN 1..3 LOOP --NUMBER OF ACT i
    << inst_loop >>
    FOR j IN 1..1000 LOOP --NUMBER OF INST j
        t_day:='3-JAN-16';
        << day_loop >>
        FOR k IN 1..260 LOOP --NUMBER OF DAYS k
            n:= dbms_random.value(1,3);
            INSERT into bdb (ACT,INST,DAY,PRICE,CURR) values (i,j,t_day,n,10.3);
            t_day:=t_day+1;
        END loop day_loop;

    END loop inst_loop;
END loop act_loop;

END;
/

使用此查询 我只得到 DAY,INST,PRICE

select day,inst,price from bdb where (act=(select max(act) from bdb))
minus
select day,inst,price from bdb where act=(select max(act)-1 from bdb);

上面的速度很快。但我想以有效的方式获得所有领域。 我想出来的有点慢,就是这个,

select 
    e1.* 
from 
    (select 
        * 
    from 
        bdb 
    where 
        (act=(select max(act) from bdb))
    )e1,
(select day,inst,price from bdb where (act=(select max(act) from bdb))
minus
select day,inst,price from bdb where act=(select max(act)-1 from bdb)) e2
where 
e1.day=e2.day and e1.inst=e2.inst;

任何人都可以就如何优化这个提出任何建议吗?或者不使用两个表的交叉连接如何获得所需的输出。帮助我;)

我需要的只是

     ACT  INST     DAY      PRI   CURR
    ------------------------------------
     3    890 05-MAR-16     3     10.3
     3    890 06-MAR-16     2     10.3
     3    890 07-MAR-16     2     10.3

     3    891 05-MAR-16     2     10.3
     3    891 06-MAR-16     1     10.3
     3    891 07-MAR-16     2     10.3

     4    890 05-MAR-16     3     10.3
     4    890 06-MAR-16     2     10.3
     4    890 07-MAR-16     1     10.3

     4    891 05-MAR-16     2     10.3
     4    891 06-MAR-16     2     10.3
     4    891 07-MAR-16     1     10.3

这里是 (890,05-MAR-16) (890,06-MAR-16) (890,06-MAR-16) (891,05-MAR-16) (891,06-MAR-16) (891,06-MAR-16) 在行动=3 价格是 3,2,2 2,1,2

but when act=4 happens
        (890,07-MAR-16) 
        (891,06-MAR-16)
        (891,07-MAR-16) 
        price values are change from what they were in act=3.
        others not change

最终我需要的是

    ACT   INST     DAY     PRI    CURR
    ------------------------------------
     4    890 07-MAR-16     1     10.3
     4    891 06-MAR-16     2     10.3
     4    891 07-MAR-16     1     10.3

【问题讨论】:

【参考方案1】:

看起来您在 day、inst 和 price 值之后,其中一行的 act 列具有整个表中的最大 act 值,但没有一行的 act 列少一超过最大行为值。

你可以试试这个:

SELECT day,
       inst,
       price
FROM   (SELECT day,
               inst,
               price,
               act,
               MAX(act) OVER () max_overall_act
        FROM   bdb)
WHERE  act IN (max_overall_act, max_overall_act -1)
GROUP BY day, inst, price
HAVING MAX(CASE WHEN act = max_overall_act THEN 1 END) = 1
AND    MAX(CASE WHEN act = max_overall_act - 1 THEN 1 END) IS NULL;

首先,子查询在整个表中找到最大的行为值。

然后我们选择所有行为值是最大值或小于该值的行。

之后,我们将行分组并找出哪些行有 act = max act val,但没有 act = max act val -1。


但是,根据您在帖子中所说的:

我已经编写了一个查询来从 bdb 中选择 *,以便仅获取最新 ACT 中 DAY、INST 组合的 PRICE 中的更新值

您提出的查询和我回答中的上述查询似乎都不符合您的要求。

我认为相反,您追求的是:

SELECT act,
       inst,
       DAY,
       price,
       curr,
       prev_price -- if desired
FROM   (SELECT act,
               inst,
               DAY,
               price,
               curr,
               LEAD(price) OVER (PARTITION BY inst, DAY ORDER BY act DESC) prev_price,
               row_number() OVER (PARTITION BY inst, DAY ORDER BY act DESC) rn
        FROM   bdb)
WHERE  rn = 1
AND    prev_price != price;

它的作用是使用 LEAD() 分析(基于递减的行为顺序)来查找每一行和每一天的前一行为行的价格,以及行号。

然后要查找最新的行为行,我们只需选择行号为 1 的行以及之前价格与当前价格不匹配的行。然后,您可以根据需要同时显示当前价格和之前的价格。

【讨论】:

感谢您的快速回复...我想我没有正确解释问题....我认为这会清楚地澄清它。更新的问题在上面 你的第一个解释是正确的......但我需要它们的 ACT 和 CURR 字段以有效的方式 道歉;我在第二个查询中错过了AND prev_price != price 条件。现在应该可以了。 感谢:D..它的工作效率很高 另一件小事......检查哪种方法更快的最佳方法是什么,是我们从这种查询中获得的执行时间......SELECT SQL_ID,EXECUTIONS, ELAPSED_TIME,CPU_TIME FROM V$SQL WHERE SQL_ID= (select /* MYCOMMENT1 / sql_id sql_text from v$sql where upper(sql_text) like '%EWTWTWT4%' and sql_text not like '%/ MYCOMMENT1 */ %');

以上是关于oracle sql查询进一步优化1的主要内容,如果未能解决你的问题,请参考以下文章

Oracle单行查询

Oracle基本查询

MySQL查询优化

Oracle过滤和排序

Mysql 数据库优化

如何优化 SQL 查询(Oracle 数据库)