I want to show a tiny effect of materializing factored subquery, which can lead to huge redo generation.
It is also a good time to taste new feature of defining PL/SQL function in the WITH clause. But it is used here only for convenience.
So, let's check how much redo is generated for materializing just one row and just one time
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual)
6 select calc.p_in + c1 into res from a;
7 return res;
8 end;
9 select calc(1) from dual;
10 /
Statistics
----------------------------------------------------------
3 recursive calls
8 db block gets
5 consistent gets
1 physical reads
572 redo size
357 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
Nothing to worry about.
But what if you have some PL/SQL function, which employs materialization, and this function is called for each 100K rows output of your report query.
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual)
6 select calc.p_in + c1 into res from a;
7 return res;
8 end;
9 select calc(rownum) from dual connect by level <=1e5;
10 /
Statistics
----------------------------------------------------------
300001 recursive calls
802222 db block gets
500000 consistent gets
100000 physical reads
57171620 redo size
611083 bytes sent via SQL*Net to client
708 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
100000 rows processed
Things become much more interesting. And it is just for one row stored in the temporary table.
One question remains, what exactly causes redo generation. Unfortunately, SQL Trace does not show anything about materialization. But doing the following run, I can infer that redo data is generated for DDL part of operation only.
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual connect by level<=1e5)
6 select calc.p_in + sum(c1) into res from a;
7 return res;
8 end;
9 select calc(1) from dual;
10 /
Statistics
----------------------------------------------------------
5 recursive calls
161 db block gets
157 consistent gets
152 physical reads
572 redo size
359 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
So, materialization feature sometimes is very useful, but it has to be applied with caution.
It is also a good time to taste new feature of defining PL/SQL function in the WITH clause. But it is used here only for convenience.
So, let's check how much redo is generated for materializing just one row and just one time
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual)
6 select calc.p_in + c1 into res from a;
7 return res;
8 end;
9 select calc(1) from dual;
10 /
Statistics
----------------------------------------------------------
3 recursive calls
8 db block gets
5 consistent gets
1 physical reads
572 redo size
357 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
Nothing to worry about.
But what if you have some PL/SQL function, which employs materialization, and this function is called for each 100K rows output of your report query.
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual)
6 select calc.p_in + c1 into res from a;
7 return res;
8 end;
9 select calc(rownum) from dual connect by level <=1e5;
10 /
Statistics
----------------------------------------------------------
300001 recursive calls
802222 db block gets
500000 consistent gets
100000 physical reads
57171620 redo size
611083 bytes sent via SQL*Net to client
708 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
100000 rows processed
Things become much more interesting. And it is just for one row stored in the temporary table.
One question remains, what exactly causes redo generation. Unfortunately, SQL Trace does not show anything about materialization. But doing the following run, I can infer that redo data is generated for DDL part of operation only.
SQL> with function calc(p_in in number) return number
2 is
3 res number;
4 begin
5 with a as (select /*+ materialize */ 1 c1 from dual connect by level<=1e5)
6 select calc.p_in + sum(c1) into res from a;
7 return res;
8 end;
9 select calc(1) from dual;
10 /
Statistics
----------------------------------------------------------
5 recursive calls
161 db block gets
157 consistent gets
152 physical reads
572 redo size
359 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
So, materialization feature sometimes is very useful, but it has to be applied with caution.
No comments:
Post a Comment