我有一个查询,其结果存储在GTT(全球临时表)和集合中。
再次从GTT中选择数据,我的成本非常低:103。
SELECT
...
FROM my_table_gtt
JOIN table2 ...
JOIN table3 ...
但是当将它从GTT切换到集合(VA - 虚拟阵列)时,成本一路飙升(78.000),但两者之间执行时间的差异非常小。
SELECT
...
FROM TABLE(CAST(my_table_va as my_table_tt))
JOIN table2 ...
JOIN table3 ...
我的问题是为什么两种方法之间的成本差异如此之大?据我所知,GTT不存储表统计信息,为什么它返回的成本比VA更高?
答案 0 :(得分:1)
全局临时表可以包含任何其他表的统计信息。事实上,它们就像任何其他表一样,它们只有临时表空间中的数据段。
在11g中,统计数据是全局的,因此它们有时会导致执行计划出现问题。在12c中,它们是基于会话的,因此每个会话都是正确的(如果可用的话)。
集合类型基数基于DB块大小,默认情况下8 kB块为8168.集合内容存储在PGA中。在复杂查询中使用集合类型来提示优化器时,提示基数是很常见的。您还可以使用扩展优化器接口来实现自己计算成本的方法。
编辑 - 添加测试:
CREATE TYPE STRINGTABLE IS TABLE OF VARCHAR2(255);
CREATE GLOBAL TEMPORARY TABLE TMP (VALUE VARCHAR2(255));
INSERT INTO TMP SELECT 'Value' || LEVEL FROM DUAL CONNECT BY LEVEL <= 1000000;
DECLARE
x STRINGTABLE;
cnt NUMBER;
BEGIN
SELECT VALUE BULK COLLECT INTO x FROM TMP;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSTIMESTAMP, 'MI:SS.FF3'));
SELECT SUM(LENGTH(VALUE)) INTO cnt FROM TMP;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSTIMESTAMP, 'MI:SS.FF3'));
SELECT SUM(LENGTH(COLUMN_VALUE)) INTO cnt FROM TABLE(x);
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSTIMESTAMP, 'MI:SS.FF3'));
END;
在这种情况下,对GTT的访问速度大约是收集速度的两倍,cca 200毫秒与我的测试机器上的400毫秒相比。当我将行数增加到10 000 000时,我得到了ORA-22813:操作数值超过了第二个查询的系统限制。
答案 1 :(得分:0)
在SQL中,集合和GTT之间最重要的区别是CBO(基于成本的优化器)对TABLE函数(kokbf $ ...)有限制,例如JPPD不能与TABLE()函数一起使用。 一些解决方法:http://orasql.org/2019/05/30/workarounds-for-jppd-with-view-and-tablekokbf-xmltable-or-json_table-functions/