Oracle调优之no_unnest和unnest用法简介 本博客介绍Oracle SQL调优的一种常用也是很实用的方法,也即/*+no_unnest */和/*+ unnest*/,介绍Oracle 的 /*+unnest */ 、 /*+ no_unnest */之前,先介绍一下Hint。 详情可以参考作者博文:https://dbaplus.cn/news-10-669-1.html ok,有了前面的必要知识后,可以介绍一下Oracle的Hint语法之no_unnest和unnest用法了 ,no_unnest、unnest显然是一对相对的用法 unnest:也即解嵌套,nest是嵌套的意思,也就是让子查询展开查询,和外部的查询进行关联、合并,从而得到执行计划 no_unnest:双重否定表肯定 unnest或者no_unnest,这两种用法具体在什么环境使用适宜?
Oracle调优之no_unnest和unnest用法简介 本博客介绍Oracle SQL调优的一种常用也是很实用的方法,也即/*+no_unnest */和/*+ unnest*/,介绍Oracle 的 /*+unnest */ 、 /*+ no_unnest */之前,先介绍一下Hint。 和unnest用法了,no_unnest、unnest显然是一对相对的用法 unnest:也即解嵌套,nest是嵌套的意思,也就是让子查询展开查询,和外部的查询进行关联、合并,从而得到执行计划 no_unnest */的形式,所以对于这两种嵌套和解嵌套查询,其用法分别为/*+ no_unnest */、/*+ unnest*/,加在子查询的select关键字后面即可,我之前博客曾经整理过Hint的常用语法,详情参考我博客 unnest或者no_unnest,这两种用法具体在什么环境使用适宜?
CUST.CUSTOMER_ID AND (CYC_CUST.UNDO_REQ_TYPE = 'N' OR CYC_CUST.UNDO_REQ_TYPE IS NULL) AND EXISTS (SELECT /*+unnest
然后客户把sql代码和升级前后的执行计划截图发给了我,我马上就知道了原因:这个sql使用了12c的标量子查询嵌套的新特性(Scalar Subquery Unnest),在2014年的一个内部技术交流中 ,我还着重讲了这个12c的新特性.于是,我很快给出了以下建议: 影响执行计划的真正参数是_optimizer_unnest_scalar_sq,可以通过/*+ OPT_PARAM('_optimizer_unnest_scalar_sq ' 'false') */的hint来修正,或者在标量子查询的select部分使用/*+ no_unnest */ ,都能解决问题. =true 1654 buffers 禁用功能: _optimizer_unnest_scalar_sq=false 77604 buffers,两者相差40倍以上(数据量越大,性能差距会更大 应该是优化器没有更好地做cost评估,把不该unnest的执行计划,强行做了unnest.
Oracle查询转换功能主要有启发式(基于规则)查询转换以及基于Cost的查询转换两种,针对子查询主要有Subquery Unnest、Push Subquery等。 如果子查询不能unnest(启发式),可以选择把子查询转换为Inline View(基于Cost);如果都不可以,那么子查询就会最后执行,可能会看到类似Filter的操作。 /*通过提示no_unnest,禁止了子查询解嵌套。 系统中存在一个参数来控制解嵌套子查询—_unnest_subquery。参数_unnest_subquery在8i中的默认设置是false,从9i开始其默认设置是true。 在11g环境下还受优化器参数_optimizer_unnest_all_subqueries控制。此外,提示UNNEST/NO_UNNEST可以控制是否进行解嵌套。
为了给每个name的tag按原始位置增加序号,需要建立以下函数,返回数组值及其对应的下标: create or replace function f_unnest_ord(anyarray, out val 前面两种是相对通用的方法,关系数据库的SQL都支持,而unnest是PostgreSQL独有的函数。 有了前面的基础,这个实现就比较简单了,只要执行下面的查询即可: select * from (select c1,split_part(unnest(c2),':',1) c2, split_part (unnest(c2),':',2) c3 from (select c1,string_to_array(c2,',') c2 from ( (c2),':',1) c2, split_part(unnest(c2),':',2) c3 test(# from (select c1,string_to_array(c2,
子查询关联集展开机能(unnest correlation set subquery) 这个机能,我在 Google 上查了一下,分享的文章特别少,可能是很少被关注到吧。 dbms_stats.gather_table_stats(user, 'T2'); exec dbms_stats.gather_table_stats(user, 'DRV'); SQL> alter session set "_optimizer_unnest_corr_set_subq SQL> alter session set "_optimizer_unnest_corr_set_subq" = TRUE; SQL> select key from drv where exists 上面的例子也可以看出来,这个机能是用隐藏参数 “_optimizer_unnest_corr_set_subq” 来控制的。
SELECT sum(od.quantity*od.price) amountFROM read_json_auto('orders.json') AS o,LATERAL UNNEST(o.order_details ) AS t(od),LATERAL UNNEST([od.product]) AS t(p)WHERE p.category = 'Electronics'为了完成这样的计算,SQL 要把子表和主表关联起来做内接连来实现过滤 而且 SPL 还能保持 JSON 的多层结构,不需要折腾 GROUP BY 和 LATERAL UNNEST 之类的复杂 SQL。 DuckDB 确实对 JSON 处理得不错,但写起来还是要倒腾 UNNEST 之类的 SQL 结构,层次一多就显得麻烦。
.* from t1 where c2 in (select /*+ NO_UNNEST */ c2 from t2); C1 C2 ---------- ------- operation id): --------------------------------------------------- 1 - filter( EXISTS (SELECT /*+ NO_UNNEST "C2"=:B1)) 3 - filter("C2"=:B1) SQL> select t1.* from t1 where c2 not in (select /*+ NO_UNNEST operation id): --------------------------------------------------- 1 - filter( NOT EXISTS (SELECT /*+ NO_UNNEST 有以下两种方法: 隐含参数 _UNNEST_SUBQUERY 设置成 false OR 最开始例子里面用到的 NO_UNNEST hint。
dvdrental=# select *,t_vals.freqs::float * t_rels.reltuples as rows from (SELECT tablename,attname,unnest (most_common_vals::text::text[]) as vals,unnest(most_common_freqs::text::float[]) as freqs FROM pg_stats with first_name as ( select *,t_vals.freqs::float as freqs_1 from (SELECT tablename,attname, unnest( most_common_vals::text::text[]) as vals, unnest(most_common_freqs::text::float[]) as freqs FROM pg_stats (most_common_vals::text::text[]) as vals, unnest(most_common_freqs::text::float[]) as freqs FROM pg_stats
Transformation TABLE_LOOKUP_BY_NL Table Lookup By Nested Loop TABLE_EXPANSION Table Expansion UNNEST unnest query block VECTOR_AGG Vector Transformation CURSOR_SHARING Cursor sharing DML DML Transformation TABLE_LOOKUP_BY_NL Table Lookup By Nested Loop TABLE_EXPANSION Table Expansion UNNEST unnest query block VECTOR_AGG Vector Transformation CLUSTER_BY_ROWID Cluster By Rowid Transformation unnest query block USE_CONCAT Or-optimization XML_REWRITE XML Rewrite CHECK_ACL_REWRITE
使用 no_unnest hint可以让执行计划产生filter,即不展开,但一般情况下使用unnest hint无法消除filter。 在SQL语句where子查询后有not in、not exists、in、exists时,CBO会尝试将子查询展开(unnest)消除filter,但是上面的例子CBO并没有做到,下面我们看下执行计划。 103001.png 我们再看下在子查询中加unnest hint的执行计划: SELECT SEGMENT_NAME,SUM(BYTES/1024/1024) m FROM DBA_SEGMENTS WHERE SEGMENT_NAME NOT IN (select /*+UNNEST */index_name from dba_indexes where UNIQUENESS ='NONUNIQUE
shelf_availability) VALUES ('D', 10, 4.1, 4.2); SELECT * FROM public.test; 行转列 SELECT name, score, unnest (ARRAY ['total_availability' :: TEXT, 'shelf_availability' :: TEXT]) AS kpi_details, unnest( ARRAY [public.test.total_availability
ActiveUsers AS( SELECT user_pseudo_id FROM`table.events_*` WHERE(SELECT value.int_value FROM UNNEST (event_params) WHERE key ='engagement_time_msec')>0 OR (SELECT value.string_value FROM UNNEST(event_params SELECT HLL_COUNT.EXTRACT( HLL_COUNT.INIT( CONCAT( user_pseudo_id,(SELECT `value` FROM UNNEST
但是如果屏蔽了某些隐含参数,还是会不一样,曾经在客户现场遇到一个case,使用exists的SQL,优化器没有自动做unnest,性能很差,加了unnest的hint后可以,改成in也可以不用加unnest 的hint就能自动做unnest。
为了解决这个问题,我们尝试了将200万行数据转换为单行返回,使用PostgreSQL的array_agg和unnest函数来优化查询。 第一次遇到Mybatis查询返回导致接口速度慢的问题。 要将 PostgreSQL 中查询出的 programhandleidlist 字段(假设这是一个数组类型)的所有元素拼接为一行,您可以使用数组聚合函数 array_agg 结合 unnest 函数。 以下是相应的 SQL 语句: SELECT array_agg(elem) AS concatenated_array FROM ( SELECT unnest(programhandleidlist 要统计每个数组中元素出现的次数,您需要首先使用 unnest 函数将数组展开为单独的行,然后使用 GROUP BY 和聚合函数(如 count)来计算每个元素的出现次数。 这里是修改后的 SQL 语句: SELECT elem, COUNT(*) AS count FROM ( SELECT unnest(programhandleidlist) AS elem
我写了一个脚本来实现查询: SELECT * , ARRAY(SELECT UNNEST(isbns) EXCEPT SELECT UNNEST(to_exclude )) , ARRAY_UPPER (ARRAY(SELECT UNNEST(isbns) EXCEPT SELECT UNNEST(to_exclude )), 1) FROM ( SELECT * , ARRAY[ GROUP BY tag ORDER BY max(popularity) DESC ) AS ttt ) AS tttt ORDER BY ARRAY_upper(ARRAY(SELECT UNNEST (arr) EXCEPT SELECT UNNEST(la)), 1) DESC; 有了这些数据,我开始建网站。
因为这是一次性工作,我决定用PostgreSQL数组,编程语言如下: SELECT * , ARRAY(SELECT UNNEST(isbns) EXCEPT SELECT UNNEST(to_exclude )) , ARRAY_UPPER(ARRAY(SELECT UNNEST(isbns) EXCEPT SELECT UNNEST(to_exclude )), 1) FROM ( SELECT BY tag ORDER BY max(popularity) DESC ) AS ttt ) AS tttt ORDER BY ARRAY_upper(ARRAY(SELECT UNNEST (arr) EXCEPT SELECT UNNEST(la)), 1) DESC; 既然已经有了所需要的数据,我开始着手建立网站。
插入失败,同时会话自动断开,在 alert 日志信息出现 ORA-07445 错误,尝试在 session 级别关闭标量子查询的自动转换功能,alter session set "_optimizer_unnest_scalar_sq 由上案例我们可知道,在 12C 中,标量子查询自动改写的功能是有隐含参数_optimizer_unnest_all_subqueries 控制,默认是 true,意味着开启,如果遇到 bug,出错或者在自动改写转换后出现性能问题时 ,可以先尝试更改为 false,或者用hint(no_unnest) 避免子查询展开。 参数的控制; ⑥ 如果在 12C 中,标量子查询优化器自动转换导致了 SQL 语句遇到 bug,出错或者再出现性能问题,可以用 alter session set "_optimizer_unnest_scalar_sq "=false 将其关闭此功能,或者用 hint no_unnest 来避免子查询展开。
+ quantile = list(quantile(y, probs)), + prob = list(probs)) %>% + unnest 0.5 9 2 2.02 1.38 0.75 10 3 2.89 -0.418 0.25 # … with 53 more rows 去掉 unnest mean(x), + quantile = list(quantile(y, probs)), + prob = list(probs)) %>% + unnest