no_unnest,push_subq用法小试

本文探讨了Oracle数据库中不同提示对SQL执行计划的影响,包括no_unnest和push_subq提示的作用,展示了如何通过这些提示调整执行计划以提高查询效率。

create table t1 as select * from dba_objects;

Table created.

create table t2 as select * from dba_objects;

Table created.

create table t3 as select * from dba_objects;

Table created.

create index w_1 on t1(object_id);

Index created.

create index w_2 on t2(object_id);

Index created.

create index w_3 on t3(object_id);

Index created.

exec dbms_stats.gather_table_stats(user,'T1');

PL/SQL procedure successfully completed.

exec dbms_stats.gather_table_stats(user,'t2');

PL/SQL procedure successfully completed.

exec dbms_stats.gather_table_stats(user,'t3');

PL/SQL procedure successfully completed.

explain plan for
  2  select t1.object_id,t1.object_name ,t2.object_type
  3   from t1 ,t2 where t1.object_id=t2.object_id and t2.object_type='TABLE'
  4   and exists ( select 1 from t3 where t3.object_name='WXH' AND t3.object_id=t1.object_id);

Explained.

select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
Plan hash value: 3087771463

---------------------------------------------------------------------------------------
| Id  | Operation                      | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |      |     1 |    61 |    79   (2)| 00:00:01 |
|   1 |  NESTED LOOPS                  |      |       |       |            |          |
|   2 |   NESTED LOOPS                 |      |     1 |    61 |    79   (2)| 00:00:01 |
|   3 |    NESTED LOOPS                |      |     1 |    48 |    77   (2)| 00:00:01 |
|   4 |     SORT UNIQUE                |      |     1 |    24 |    74   (0)| 00:00:01 |
|*  5 |      TABLE ACCESS FULL         | T3   |     1 |    24 |    74   (0)| 00:00:01 |
|   6 |     TABLE ACCESS BY INDEX ROWID| T1   |     1 |    24 |     2   (0)| 00:00:01 |
|*  7 |      INDEX RANGE SCAN          | W_1  |     1 |       |     1   (0)| 00:00:01 |
|*  8 |    INDEX RANGE SCAN            | W_2  |     1 |       |     1   (0)| 00:00:01 |
|*  9 |   TABLE ACCESS BY INDEX ROWID  | T2   |     1 |    13 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter("T3"."OBJECT_NAME"='WXH')
   7 - access("T3"."OBJECT_ID"="T1"."OBJECT_ID")
   8 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
   9 - filter("T2"."OBJECT_TYPE"='TABLE')

看到ORACLE把子查询展开和t3进行了join。看看使用no_unnest提示的情况。

explain plan for
  2  select t1.object_id,t1.object_name ,t2.object_type
  3   from t1 ,t2 where t1.object_id=t2.object_id and t2.object_type='TABLE'
  4   and exists ( select /*+ no_unnest */1 from t3 where t3.object_name='WXH' AND t3.object_id=t1.object_id);

Explained.

select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2811354197

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |    37 |  3609   (1)| 00:00:44 |
|*  1 |  FILTER                      |      |       |       |            |          |
|*  2 |   HASH JOIN                  |      |  3458 |   124K|   149   (1)| 00:00:02 |
|*  3 |    TABLE ACCESS FULL         | T2   |  3474 | 45162 |    74   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL         | T1   | 19046 |   446K|    74   (0)| 00:00:01 |
|*  5 |   TABLE ACCESS BY INDEX ROWID| T3   |     1 |    24 |     2   (0)| 00:00:01 |
|*  6 |    INDEX RANGE SCAN          | W_3  |     1 |       |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "T3" "T3" WHERE
              "T3"."OBJECT_ID"=:B1 AND "T3"."OBJECT_NAME"='WXH'))
   2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
   3 - filter("T2"."OBJECT_TYPE"='TABLE')
   5 - filter("T3"."OBJECT_NAME"='WXH')
   6 - access("T3"."OBJECT_ID"=:B1)

使用no_unnest提示后,子查询将不被展开,T1.T2完成join后,再通过filter操作进行过滤。

再看看push_subq来将子查询强制先进行join-filter。

explain plan for
  2  select /*+ push_subq(@tmp)  */t1.object_id,t1.object_name ,t2.object_type
  3   from t1 ,t2 where t1.object_id=t2.object_id and t2.object_type='TABLE'
  4   and exists ( select /*+ qb_name(tmp) no_unnest */1 from t3 where t3.object_name='WXH' AND t3.object_id=t1.object_id);

Explained.

select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2880557960

--------------------------------------------------------------------------------------
| Id  | Operation                     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |      |   948 | 35076 |   151   (1)| 00:00:02 |
|*  1 |  HASH JOIN                    |      |   948 | 35076 |   149   (1)| 00:00:02 |
|*  2 |   TABLE ACCESS FULL           | T1   |   952 | 22848 |    74   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| T3   |     1 |    24 |     2   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | W_3  |     1 |       |     1   (0)| 00:00:01 |
|*  5 |   TABLE ACCESS FULL           | T2   |  3474 | 45162 |    74   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
   2 - filter( EXISTS (SELECT /*+ PUSH_SUBQ NO_UNNEST QB_NAME ("TMP") */ 0
              FROM "T3" "T3" WHERE "T3"."OBJECT_ID"=:B1 AND "T3"."OBJECT_NAME"='WXH'))
   3 - filter("T3"."OBJECT_NAME"='WXH')
   4 - access("T3"."OBJECT_ID"=:B1)
   5 - filter("T2"."OBJECT_TYPE"='TABLE')

这里的执行计划显示的不够专业。可能是ORACLE怕格式不好看,FILTER操作被隐藏了。

--------------------------------------------------------------------------------------
| Id  | Operation                     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |      |   948 | 35076 |   151   (1)| 00:00:02 |
|*  1 | HASH JOIN                     |      |   948 | 35076 |   149   (1)| 00:00:02 |
|     |  FILTER                       |      |       |       |    00      | 00:00:01 |
|*  2 |   TABLE ACCESS FULL           | T1   |   952 | 22848 |    74   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| T3   |     1 |    24 |     2   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | W_3  |     1 |       |     1   (0)| 00:00:01 |
|*  5 |  TABLE ACCESS FULL            | T2   |  3474 | 45162 |    74   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22034023/viewspace-689861/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/22034023/viewspace-689861/

### PostgreSQL 中 `string_to_array` 和 `unnest` 的使用场景及 SQL 子句位置 #### 1. `string_to_array` 函数 `string_to_array` 是 PostgreSQL 提供的一个函数,用于将字符串转换为数组。该函数接受两个参数:第一个是要转换的字符串,第二个是分隔符。它通常出现在 **SELECT** 子句或 **FROM** 子句中作为数据源的一部分。 例如: ```sql SELECT string_to_array('apple,banana,cherry', ',') AS fruits; ``` 在这个例子中,`string_to_array` 将字符串 `'apple,banana,cherry'` 转换成了一个数组 `{apple,banana,cherry}`[^1]。 #### 2. `unnest` 函数 `unnest` 函数的作用是从数组中提取元素并将其展平为多行的结果集。它可以与 `string_to_array` 结合使用,从而实现从单个字符串到多行记录的转化过程。`unnest` 主要应用于 **FROM** 子句中,以便生成新的虚拟表结构。 示例代码如下所示: ```sql SELECT unnest(string_to_array('apple,banana,cherry', ',')) AS fruit; ``` 此处,`unnest` 接收由 `string_to_array` 返回的数组,并将其分解成三行独立的数据项。 #### 3. 组合使用场景 当需要查找某些特定条件的产品或者标签时,这两个函数可以联合起来发挥作用。假设有一张存储商品及其对应标签信息的表格,每件商品可能关联多个标签(以逗号分隔的形式保存在一个字段里)。此时就可以利用 `string_to_array` 把这些标签转化为数组形式,接着再通过 `unnest` 进一步拆解开来逐一比较分析。 更进一步地,在 Postgres 9.4 及以上版本中引入了 `WITH ORDINALITY` 功能扩展支持,允许我们在调用诸如 `unnest()` 此类集合返回型函数的同时附加额外的一列序号指示当前所在位置编号[^3]。 下面给出一段综合运用上述知识点的实际案例演示: ```sql SELECT t.id, a.elem, a.nr FROM tbl AS t LEFT JOIN LATERAL unnest(string_to_array(t.elements, ',')) WITH ORDINALITY AS a(elem, nr) ON TRUE; ``` 在此查询片段当中,`string_to_array` 配合 `unnest` 达到了把原先压缩在一起的属性列表分离出来的目的;而新增加的 `nr` 字段则标明了各项原本位于原串中的次序关系[^3]。 --- ### 总结说明 综上所述,`string_to_array` 多数情况下会出现在 **SELECT** 或者 **FROM** 子句内部参与计算流程设计之中;至于 `unnest` 则几乎总是固定搭配于 **FROM** 子句之下负责构造临时视图框架供给后续操作环节调用之便。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值