查询成本:全局临时表与集合(虚拟数组)

Posted

技术标签:

【中文标题】查询成本:全局临时表与集合(虚拟数组)【英文标题】:Query cost: Global Temporary Tables vs. Collections (Virtual Arrays) 【发布时间】:2015-12-15 17:22:40 【问题描述】:

我有一个查询,其结果存储在 GTT(全局临时表)和集合中。

再次从GTT中选择数据,我得到一个非常小的成本:103。

SELECT
    ...
FROM my_table_gtt
JOIN table2 ...
JOIN table3 ...

但是当从 GTT 切换到 Collection(VA - Virtual Array)时,成本飙升(78.000),但两者之间的执行时间差异非常小。

SELECT
    ...
FROM TABLE(CAST(my_table_va as my_table_tt))
JOIN table2 ...
JOIN table3 ...

我的问题是,为什么这两种方法的成本差异如此之大?据我所知,GTT 不存储表统计信息,那么为什么它返回的成本比 VA 更好?

【问题讨论】:

【参考方案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 的速度大约是收集速度的两倍,在我的测试机器上大约为 200 毫秒,而 400 毫秒。当我将行数增加到 10 000 000 时,我得到了 ORA-22813:操作数值超出了第二个查询的系统限制。

【讨论】:

所以收集方法成本实际上会显示将数据存储在内存中的成本,以 kB 为单位?我问这个是因为我试图比较两种方法之间的性能(执行时间很明显,因为它们大多是相等的),但是还有其他可以比较的指标吗? 不,这与它无关。据我所知,DB 块大小是驱动集合默认成本的唯一因素。对于简单的 TABLE FULL SCAN,成本大约是要访问的块数。不要太在意成本,它只用于比较同一查询的执行计划。更重要的是集合的基数,它会影响执行计划,选择不同的访问路径、连接类型或连接顺序,从而导致非常不理想的结果。 所以,这意味着只要连接顺序、连接类型等是相同(或最好..)。 由于 GTT 是常规数据对象,它可以保存大量数据,因此集合在内存对象中,因此您受到更多限制。我还没有对它进行基准测试,但我认为在你达到一些内存限制之前它应该是相似的。 据我所知,只要合适,集合就会将数据存储在内存中,如果不合适,它会将数据“溢出”到 PGA 上。【参考方案2】:

集合和 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/

【讨论】:

这是实际信息吗?它适用于哪个版本的 Oracle DB?

以上是关于查询成本:全局临时表与集合(虚拟数组)的主要内容,如果未能解决你的问题,请参考以下文章

临时表,临时表什么时候删除

DB2 将大型物理表与小型全局临时表连接起来

Mysql 临时表+视图

数据库——创建局部临时表和全局临时表

使用 Laravel 的查询构建器或 Eloquent 将一个表与一个临时表进行内部连接

临时表与中间表