【问题标题】:View Performance查看性能
【发布时间】:2022-11-02 14:16:07
【问题描述】:

我需要对具有大日期集(300 GB)的表的列执行一些计算。并返回该值。

基本上我需要在该表上创建一个视图。表有 21 年的数据,并按日期列(每日)分区。我们不能将日期条件放在视图的查询上,用户将在视图执行时将过滤器放在运行时。

例如:

创建视图 v_view 为 从表中选择 *;

不,我想查询 View like 选择 * v_view where ts_date 在 '1-Jan-19' 和 '1-Jan-20' 之间

Oracle 如何在内部执行上述语句?它会先执行视图查询,然后再对其进行日期过滤吗?

如果是这样会不会有性能问题?以及如何解决这个问题?

【问题讨论】:

    标签: oracle oracle12c oracle19c


    【解决方案1】:

    oracle 首先生成视图,然后应用过滤器。您可以创建一个用户可以插入输入的函数。该函数产生一个创建查询,如果您运行查询,则将创建视图。赶紧跑:

    create or replace function fnc_x(where_condition in varchar2) 
    return varchar2
    as
    
    begin
    
    return ' CREATE OR REPLACE VIEW sup_orders AS
      SELECT suppliers.supplier_id, orders.quantity, orders.price
      FROM suppliers
      INNER JOIN orders
      ON suppliers.supplier_id = orders.supplier_id
      '||where_condition||'  ';
    end fnc_x;  
    

    这个函数应该运行。输入函数是这样的字符串:

    ''WHERE suppliers.supplier_name = Microsoft''
    

    那么你应该运行这样的块来运行函数的结果:

    cl scr
    set SERVEROUTPUT ON
    declare
     szSql varchar2(3000);
     crte_vw varchar2(3000);
    begin
      szSql := 'select fnc_x(''WHERE suppliers.supplier_name = Microsoft'') from dual';
      dbms_output.put_line(szSql);
      execute immediate  szSql  into crte_vw; -- generate 'create view' command that is depended on user's where_condition
      dbms_output.put_line(crte_vw);
      execute immediate crte_vw ; -- create the view
    end;
    

    这样,您只需要从用户那里收到 where_condition。

    【讨论】:

    • 如果多个用户将使用该功能,则可能会引发错误。
    • 很好的提示,但是当两个用户想要创建或替换相同的功能或过程时也会发生这种情况。对于这个问题,您可以定义一个用户查询队列并编写一个过程来处理该队列。阿斯蒂特瓦
    【解决方案2】:

    Oracle 可以在简单视图中“推送”谓词,然后可以使用这些谓词来启用分区修剪以获得最佳性能。您几乎无需担心 Oracle 将首先运行什么 - 它会为您找出最佳顺序。 Oracle 不需要盲目地构建查询的第一步,然后将所有结果发送到第二步。下面的示例架构和查询演示了在查询分区表上的视图时如何仅使用最少量的分区。

    --drop table table1;
    
    --Create a daily-partitioned table.
    create table table1(id number, ts_date date)
    partition by range(ts_date)
    interval (numtodsinterval(1, 'day'))
    (
        partition p1 values less than (date '2000-01-01')
    );
    
    --Insert 1000 values, each in a separate day and partition.
    insert into table1
    select level, date '2000-01-01' + level
    from dual
    connect by level <= 1000;
    
    --Create a simple view on the partitioned table.
    create or replace view v_view as select * from table1;
    

    以下说明计划显示“Pstart”和“Pstop”设置为 3 和 4,这意味着该查询仅使用了许多分区中的 2 个。

    --Generate an explain plan for a simple query on the view.
    explain plan for
    select * from v_view where ts_date between date '2000-01-02' and date '2000-01-03';
    
    --Show the explain plan.
    select * from table(dbms_xplan.display(format => 'basic +partition'));
    
    Plan hash value: 434062308
     
    -----------------------------------------------------------
    | Id  | Operation                | Name   | Pstart| Pstop |
    -----------------------------------------------------------
    |   0 | SELECT STATEMENT         |        |       |       |
    |   1 |  PARTITION RANGE ITERATOR|        |     3 |     4 |
    |   2 |   TABLE ACCESS FULL      | TABLE1 |     3 |     4 |
    -----------------------------------------------------------
    

    然而,分区修剪和谓词推送并不总是在我们认为应该起作用的时候起作用。我们可以帮助优化器做的一件事是使用日期文字而不是看起来像日期的字符串。例如,替换 '1-Jan-19'date '2019-01-01'。当我们使用 ANSI 日期文字时,没有歧义,Oracle 更有可能使用分区修剪。

    【讨论】:

      猜你喜欢
      • 2018-12-03
      • 2020-04-27
      • 1970-01-01
      • 2021-02-26
      • 2021-04-11
      • 1970-01-01
      • 2014-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多