with MATERIALIZE inline cardinality 联合使用 literals vs bind variables

Applies To

All Users

Summary

NOTE: In the images and/or the document content below, the user information and data used represents fictitious data from the Oracle sample schema(s) or Public Documentation delivered with an Oracle database product. Any similarity to actual persons, living or dead, is purely coincidental and not intended in any manner.

If similar subqueries appear more than once in a sql, it is worth trying to rewrite the query using WITH subquery.
There are some things we should consider in order to get the benefit from it.

Solution

Subquery Factoring

Subquery Factoring or WITH clause enables you to assign a name to a subquery block that can then be referenced in multiple places in the query.
This subquery will be transformed as either a temporary table (materialization) or an inline view

Things to Consider when Deciding to Use Subquery Factoring

  • Subquery Factoring can simplify the query statement making the format of the query clearer and more readable.
  • As it eliminates the repeated scan of the same table, it may reduce physical I/O and logical reads.
    This is more noticeable when retrieving a large amount of data.
  • It causes some recursive calls and "db block gets"(reads in current mode), and generates some redo data because it creates a temporary table during execution.
  • It runs faster only if the total I/O is less than the plan that does not use materialization

Examples of Subquery Factoring

Example 1
SELECT ...
FROM A, B, C
WHERE ...
AND A.a in (select col from T1, T2, T3 where ...)
AND B.b in (select col from T1, T2, T3 where ...)
AND C.c in (select col from T1, T2, T3 where ...);

can be written as:
WITH S AS (select col from T1, T2, T3 where ...)
SELECT ...
FROM A, B, C
WHERE ...
AND A.a in (select col from S)
AND B.b in (select col from S)
AND C.c in (select col from S);

Example 2
SELECT ...
FROM (select ... from T1 ...) S1,
(select ... from T2 ...) S2,
(select ... from T3 ...) S3
WHERE ... ;

can be written as:
WITH S1 AS (select ... from T1 ...),
S2 AS (select ... from T2 ...),
S3 AS (select ... from T3 ...)
SELECT ...
FROM S1, S2, S3
WHERE ... ;

Influencing the Plan with Hints and Parameters

The decision whether to transfer the subquery into an inline view or a temporary table is done before the optimization and is determined by certain rules. However the decision can be influenced by including a hint in the WITH clause or by setting the parameter "_with_subquery".

Hints
  • /*+ MATERIALIZE */ : The subquery is materialized into a temporary table
    WITH S AS (select /*+ MATERIALIZE */ col from T1, T2, T3 where ...)
    SELECT ...
    FROM A, B, C
    WHERE ...
    AND A.a in (select col from S)
    AND B.b in (select col from S)
    AND C.c in (select col from S);

  • /*+ INLINE */ : The subquery is inlined and not materialized
    WITH S AS (select /*+ INLINE */ col from T1, T2, T3 where ...)
    SELECT ...
    FROM A, B, C
    WHERE ...
    AND A.a in (select col from S)
    AND B.b in (select col from S)
    AND C.c in (select col from S);

Optimizer Parameter

The parameter "_WITH_SUBQUERY" can have the following values:

  • optimizer : Let the optimizer choose (default)
  • materialize: Always materialize the WITH subquery
  • inline : Always inline.

The parameter can be set in pfile/spfile, at system level or at session level.

Demonstration

This test was done in SH demo schema.

Create 2 tables PRODUCTS2 and PRODUCTS3
connect sh/sh

create table products2 as select * from products;
create table products3 as select * from products;

Query 1 - Without Subquery Factoring

select P.prod_name, S.sale_count
from products P, (select prod_id, count(*) sale_count from sales group by prod_id) S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products2 P, (select prod_id, count(*) sale_count from sales group by prod_id) S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products3 P, (select prod_id, count(*) sale_count from sales group by prod_id) S
where P.prod_id = S.prod_id;


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 216 | 13536 | 862 (97)| 00:00:01 | | |
| 1 | UNION-ALL | | | | | | | |
|* 2 | HASH JOIN | | 72 | 4032 | 287 (90)| 00:00:01 | | |
| 3 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 2 (0)| 00:00:01 | | |
| 4 | VIEW | | 72 | 1872 | 285 (90)| 00:00:01 | | |
| 5 | HASH GROUP BY | | 72 | 288 | 285 (90)| 00:00:01 | | |
| 6 | PARTITION RANGE ALL | | 918K| 3589K| 29 (0)| 00:00:01 | 1 | 28 |
| 7 | BITMAP CONVERSION COUNT | | 918K| 3589K| 29 (0)| 00:00:01 | | |
| 8 | BITMAP INDEX FAST FULL SCAN| SALES_PROD_BIX | | | | | 1 | 28 |
|* 9 | HASH JOIN | | 72 | 4752 | 287 (90)| 00:00:01 | | |
| 10 | TABLE ACCESS FULL | PRODUCTS2 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 11 | VIEW | | 72 | 1872 | 285 (90)| 00:00:01 | | |
| 12 | HASH GROUP BY | | 72 | 288 | 285 (90)| 00:00:01 | | |
| 13 | PARTITION RANGE ALL | | 918K| 3589K| 29 (0)| 00:00:01 | 1 | 28 |
| 14 | BITMAP CONVERSION COUNT | | 918K| 3589K| 29 (0)| 00:00:01 | | |
| 15 | BITMAP INDEX FAST FULL SCAN| SALES_PROD_BIX | | | | | 1 | 28 |
|* 16 | HASH JOIN | | 72 | 4752 | 287 (90)| 00:00:01 | | |
| 17 | TABLE ACCESS FULL | PRODUCTS3 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 18 | VIEW | | 72 | 1872 | 285 (90)| 00:00:01 | | |
| 19 | HASH GROUP BY | | 72 | 288 | 285 (90)| 00:00:01 | | |
| 20 | PARTITION RANGE ALL | | 918K| 3589K| 29 (0)| 00:00:01 | 1 | 28 |
| 21 | BITMAP CONVERSION COUNT | | 918K| 3589K| 29 (0)| 00:00:01 | | |
| 22 | BITMAP INDEX FAST FULL SCAN| SALES_PROD_BIX | | | | | 1 | 28 |

Predicate Information (identified by operation id):

2 - access("P"."PROD_ID"="S"."PROD_ID")
9 - access("P"."PROD_ID"="S"."PROD_ID")
16 - access("P"."PROD_ID"="S"."PROD_ID")

Statistics

0 recursive calls
0 db block gets
251 consistent gets
0 physical reads
0 redo size
9191 bytes sent via SQL*Net to client
573 bytes received via SQL*Net from client
16 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
216 rows processed

Query 1 - With Subquery Factoring

set autotrace on

with V_SALE
as (select prod_id, count(*) sale_count from sales group by prod_id)
select P.prod_name, S.sale_count
from products P, V_SALE S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products2 P, V_SALE S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products3 P, V_SALE S
where P.prod_id = S.prod_id;


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 216 | 13536 | 14 (72)| 00:00:01 | | |
| 1 | TEMP TABLE TRANSFORMATION | | | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6608_1A3773F | | | | | | |
| 3 | HASH GROUP BY | | 72 | 288 | 285 (90)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 918K| 3589K| 29 (0)| 00:00:01 | 1 | 28 |
| 5 | BITMAP CONVERSION COUNT | | 918K| 3589K| 29 (0)| 00:00:01 | | |
| 6 | BITMAP INDEX FAST FULL SCAN| SALES_PROD_BIX | | | | | 1 | 28 |
| 7 | UNION-ALL | | | | | | | |
|* 8 | HASH JOIN | | 72 | 4032 | 5 (20)| 00:00:01 | | |
| 9 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 2 (0)| 00:00:01 | | |
| 10 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6608_1A3773F | 72 | 288 | 2 (0)| 00:00:01 | | |
|* 12 | HASH JOIN | | 72 | 4752 | 5 (20)| 00:00:01 | | |
| 13 | TABLE ACCESS FULL | PRODUCTS2 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 14 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6608_1A3773F | 72 | 288 | 2 (0)| 00:00:01 | | |
|* 16 | HASH JOIN | | 72 | 4752 | 5 (20)| 00:00:01 | | |
| 17 | TABLE ACCESS FULL | PRODUCTS3 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 18 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 19 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6608_1A3773F | 72 | 288 | 2 (0)| 00:00:01 | | |

Predicate Information (identified by operation id):

8 - access("P"."PROD_ID"="S"."PROD_ID")
12 - access("P"."PROD_ID"="S"."PROD_ID")
16 - access("P"."PROD_ID"="S"."PROD_ID")

Statistics

2 recursive calls
8 db block gets
114 consistent gets
1 physical reads
804 redo size
9191 bytes sent via SQL*Net to client
573 bytes received via SQL*Net from client
16 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
216 rows processed

Query 2 - Without Subquery Factoring

select P.prod_name, S.sale_count
from products P, (select prod_id, count(*) sale_count from sales where amount_sold <= 10 group by prod_id) S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products2 P, (select prod_id, count(*) sale_count from sales where amount_sold <= 10 group by prod_id) S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products3 P, (select prod_id, count(*) sale_count from sales where amount_sold <= 10 group by prod_id) S
where P.prod_id = S.prod_id;


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 216 | 13536 | 871 (78)| 00:00:01 | | |
| 1 | UNION-ALL | | | | | | | |
|* 2 | HASH JOIN | | 72 | 4032 | 290 (34)| 00:00:01 | | |
| 3 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 2 (0)| 00:00:01 | | |
| 4 | VIEW | | 72 | 1872 | 288 (34)| 00:00:01 | | |
| 5 | HASH GROUP BY | | 72 | 648 | 288 (34)| 00:00:01 | | |
| 6 | PARTITION RANGE ALL| | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 7 | TABLE ACCESS FULL | SALES | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 8 | HASH JOIN | | 72 | 4752 | 290 (34)| 00:00:01 | | |
| 9 | TABLE ACCESS FULL | PRODUCTS2 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 10 | VIEW | | 72 | 1872 | 288 (34)| 00:00:01 | | |
| 11 | HASH GROUP BY | | 72 | 648 | 288 (34)| 00:00:01 | | |
| 12 | PARTITION RANGE ALL| | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 13 | TABLE ACCESS FULL | SALES | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 14 | HASH JOIN | | 72 | 4752 | 290 (34)| 00:00:01 | | |
| 15 | TABLE ACCESS FULL | PRODUCTS3 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 16 | VIEW | | 72 | 1872 | 288 (34)| 00:00:01 | | |
| 17 | HASH GROUP BY | | 72 | 648 | 288 (34)| 00:00:01 | | |
| 18 | PARTITION RANGE ALL| | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 19 | TABLE ACCESS FULL | SALES | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |

Predicate Information (identified by operation id):

2 - access("P"."PROD_ID"="S"."PROD_ID")
7 - filter("AMOUNT_SOLD"<=10)
8 - access("P"."PROD_ID"="S"."PROD_ID")
13 - filter("AMOUNT_SOLD"<=10)
14 - access("P"."PROD_ID"="S"."PROD_ID")
19 - filter("AMOUNT_SOLD"<=10)

Statistics

0 recursive calls
0 db block gets
4919 consistent gets
4857 physical reads
0 redo size
1675 bytes sent via SQL*Net to client
430 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
30 rows processed

Query 2 - With Subquery Factoring

with V_SALE
as (select prod_id, count(*) sale_count from sales where amount_sold <= 10 group by prod_id)
select P.prod_name, S.sale_count
from products P, V_SALE S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products2 P, V_SALE S
where P.prod_id = S.prod_id
union all
select P.prod_name, S.sale_count
from products3 P, V_SALE S
where P.prod_id = S.prod_id;


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 216 | 13536 | 14 (72)| 00:00:01 | | |
| 1 | TEMP TABLE TRANSFORMATION | | | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D660A_1A3773F | | | | | | |
| 3 | HASH GROUP BY | | 72 | 648 | 288 (34)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
|* 5 | TABLE ACCESS FULL | SALES | 2118 | 19062 | 287 (34)| 00:00:01 | 1 | 28 |
| 6 | UNION-ALL | | | | | | | |
|* 7 | HASH JOIN | | 72 | 4032 | 5 (20)| 00:00:01 | | |
| 8 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 2 (0)| 00:00:01 | | |
| 9 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 10 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660A_1A3773F | 72 | 648 | 2 (0)| 00:00:01 | | |
|* 11 | HASH JOIN | | 72 | 4752 | 5 (20)| 00:00:01 | | |
| 12 | TABLE ACCESS FULL | PRODUCTS2 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 13 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660A_1A3773F | 72 | 648 | 2 (0)| 00:00:01 | | |
|* 15 | HASH JOIN | | 72 | 4752 | 5 (20)| 00:00:01 | | |
| 16 | TABLE ACCESS FULL | PRODUCTS3 | 72 | 2880 | 2 (0)| 00:00:01 | | |
| 17 | VIEW | | 72 | 1872 | 2 (0)| 00:00:01 | | |
| 18 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660A_1A3773F | 72 | 648 | 2 (0)| 00:00:01 | | |

Predicate Information (identified by operation id):

5 - filter("AMOUNT_SOLD"<=10)
7 - access("P"."PROD_ID"="S"."PROD_ID")
11 - access("P"."PROD_ID"="S"."PROD_ID")
15 - access("P"."PROD_ID"="S"."PROD_ID")

Statistics

2 recursive calls
8 db block gets
1657 consistent gets
1620 physical reads
804 redo size
1675 bytes sent via SQL*Net to client
430 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
30 rows processed

Documentation

Oracle® Database SQL Language Reference
12c Release 1 (12.1)
subquery_factoring_clause

Restriction

Distributed transactions are not supported for temporary tables.
Query having WITH clause will be transformed as either a temporary table (materialization) or an inline view.

Note: The following fixes should be applied if query would be transformed as a temporary table (materialization):

<Document 9399589.8> "WITH" subqueries cannot be materialized inside a global transaction
9706532.8 "WITH" subqueries cannot be materialized inside a global transaction (or PLSQL RPC over DBlink)

如果使用变量,Oracle不知道with as 返回结果,可以使用

SELECT /*+ cardinality(mem,200000) */ 明确告知Oracle返回多少行,

相关推荐
七夜zippoe3 小时前
DolphinDB分区策略:VALUE分区详解
数据库·oracle·分区·value·dolphindb
NCIN EXPE7 小时前
MySQL--》理解锁机制中的并发控制与优化策略
数据库·mysql·oracle
Lyyaoo.7 小时前
缓存穿透/雪崩/击穿
数据库·缓存·oracle
byoass21 小时前
企业云盘与设计软件深度集成:AutoCAD/Revit/SolidWorks插件开发与API集成实战
服务器·网络·数据库·安全·oracle·云计算
晴天¥1 天前
Oracle体系结构之物理存储结构(控制、数据、参数、密码、重做日志等文件)
数据库·oracle
大江东去浪淘尽千古风流人物1 天前
【UV-SLAM】eLSD/LBD 数据维度 UV-SLAM吸收借鉴
数据库·线性代数·oracle·矩阵·uv·augmented reality
FreeGo~1 天前
【MySQL数据库】数据库基础第一篇
数据库·mysql·oracle
TeDi TIVE1 天前
MySQL四种备份表的方式
mysql·adb·oracle
大迪deblog2 天前
系统架构师-数据库-数据库设计
数据库·oracle·系统架构
东风破1372 天前
DM8达梦数据库备份、恢复原理介绍
数据库·oracle·dm达梦数据库