不使用DENSE_RANK重写查询

时间:2019-11-25 13:43:40

标签: oracle

我有一个非常慢的查询,并尝试通过使用实例化视图来优化响应时间。但是有一部分与快速刷新的一般限制不兼容。 如何在没有DENSE_RANK的情况下重写它?

create table t (id,object_id,log_cre_date) as        
select 1,2,to_date('18/5/2010, 08:00','dd/mm/yyyy, hh:mi') from dual union all
select 2,2,to_date('18/5/2010, 10:00','dd/mm/yyyy, hh mi') from dual union all
select 3,3,to_date('18/5/2010, 11:00','dd/mm/yyyy, hh mi') from dual union all
select 4,3,to_date('18/5/2010, 12:10','dd/mm/yyyy, hh mi') from dual union all
select 5,4,to_date('18/5/2010, 12:20','dd/mm/yyyy, hh mi') from dual union all
select 6,4,to_date('18/5/2010, 11:30','dd/mm/yyyy, hh mi') from dual;

SELECT
    MAX(t.id) KEEP(DENSE_RANK FIRST ORDER BY log_cre_date ASC) id,
    t.object_id
FROM
    t
GROUP BY
    t.object_id

3 个答案:

答案 0 :(得分:1)

我不确定接受的答案是否可以快速刷新。这绝对是一个查询:

SELECT max(cast(to_char(t.log_cre_date,'YYYYMMDDHH24MISS') || lpad(t.id,30,'0') as varchar2(80))) maxid,
       t.object_id,
       COUNT(*) cnt
FROM   t
GROUP BY t.object_id;

这个想法是将id附加到log_cre_date并采用串联的最大值。这样,您就可以提取以后需要的id

因此,要获得id,您可以这样做:

SELECT to_char(substr(maxid,-30)) id, object_id 
FROM your_materialized_view;

您可以考虑将其隐藏起来。

这是一个完整的例子:

创建基表

DROP TABLE t;

create table t (id,object_id,log_cre_date) as        
select 1,2,to_date('18/5/2010, 08:00','dd/mm/yyyy, hh:mi') from dual union all
select 2,2,to_date('18/5/2010, 10:00','dd/mm/yyyy, hh mi') from dual union all
select 3,3,to_date('18/5/2010, 11:00','dd/mm/yyyy, hh mi') from dual union all
select 4,3,to_date('18/5/2010, 12:10','dd/mm/yyyy, hh mi') from dual union all
select 5,4,to_date('18/5/2010, 12:20','dd/mm/yyyy, hh mi') from dual union all
select 6,4,to_date('18/5/2010, 11:30','dd/mm/yyyy, hh mi') from dual;

添加一些限制以允许快速刷新MV

ALTER TABLE t MODIFY id NOT NULL;

ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY ( id );

创建快照日志以启用快速刷新

--DROP MATERIALIZED VIEW LOG ON t;

CREATE MATERIALIZED VIEW LOG ON t WITH ROWID, PRIMARY KEY (OBJECT_ID, LOG_CRE_DATE) INCLUDING NEW VALUES;

创建实例化视图(注意选择列表中存在COUNT(*)。重要!

--DROP MATERIALIZED VIEW t_mv;

CREATE MATERIALIZED VIEW t_mv
  REFRESH FAST ON COMMIT AS
SELECT max(cast(to_char(t.log_cre_date,'YYYYMMDDHH24MISS') || lpad(t.id,30,'0') as varchar2(80))) maxid,
       t.object_id,
       COUNT(*) cnt
FROM   t
GROUP BY t.object_id;

测试一下

select to_number(substr(maxid,-30)) id, object_id
from t_mv;
+----+-----------+
| ID | OBJECT_ID |
+----+-----------+
|  2 |         2 |
|  4 |         3 |
|  5 |         4 |
+----+-----------+
DELETE FROM t WHERE id = 5;

COMMIT;

select to_number(substr(maxid,-30)) id, object_id
from t_mv;
+----+-----------+
| ID | OBJECT_ID |
+----+-----------+
|  4 |         3 |
|  5 |         4 |
|  1 |         2 |    -- Now ID #1 is the latest for object_id 2
+----+-----------+

答案 1 :(得分:0)

我遇到了限制,但不确定以下查询是否有效。

尝试一下,让我们知道它是否有效。

Select t.id, t.object_id from
T join
(SELECT
    min(log_cre_date) mindt,
    t.object_id
FROM
    t
GROUP BY
    t.object_id) t1
On t.object_id = t1.object_id
And t.log_cre_date = t1.mindt;

干杯!

答案 2 :(得分:0)

也许此查询将运行得更快:

select object_id, id
from (
    select object_id, first_value(id) over(partition by object_id order by log_cre_date) as id
    from t
)
group by object_id, id;

希望有帮助!