SQL 查询优化:标量子查询是不是会影响性能?

Posted

技术标签:

【中文标题】SQL 查询优化:标量子查询是不是会影响性能?【英文标题】:SQL Query optimization : is scalar subqueries killing the performance?SQL 查询优化:标量子查询是否会影响性能? 【发布时间】:2018-07-21 11:33:50 【问题描述】:

我需要查询优化方面的帮助。

下面提到的查询只是一个示例。实际查询有 50 多个标量子查询。基表 table_xyz 有超过 500 万条记录。

SELECT 
    id,
    seq,
    (
        SELECT
            function_abc(t.id,t.seq,115501)
        FROM
            dual
    ) AS txt_dosage_comments,
    (
        SELECT
            function_abc(t.id,t.seq,115502)
        FROM
            dual
    ) AS fld_txt_total_therapy_duration

FROM
    table_xyz t;

请查看当前解释计划的截图

function_abc() 从另一个拥有 1 亿条记录的表中读取数据。 table1 已在 (id, seq, field_id, language) 字段上编入索引。一个 (id, seq) 对的行中可以有多个记录,这就是为什么有一个循环来连接它们并形成一个字符串。

这是函数的样子:

    FUNCTION function_abc (
        pi_id     int,
        pi_seq    int,
        pi_field_id   int
    ) RETURN CLOB AS
        l_result   CLOB := NULL;
    BEGIN
        FOR rec IN (
            SELECT
                text
            FROM
table_1
            WHERE
                id = pi_id
                AND   seq = pi_seq
                AND   language = '001'
                AND   field_id = pi_field_id
            ORDER BY
                seq
        ) LOOP
            l_result := concat(l_result,rec.text);
        END LOOP;

        RETURN l_result;
    END;

使用 Oracle 12c。

【问题讨论】:

@APC 我已经更新了问题并添加了函数的定义。 表已在id、seq、field_id、语言字段中建立索引 天啊。五十多个多行选择,带有一个连接 CLOB 的循环。 伤心地摇头。所以,这里的业务逻辑不清晰,很难提出改进建议。一件事:您的查询加入了seq = pi_seq,这表明了 1:1 映射。那么为什么要循环呢?或者如果每个seq 有多个行,order by 子句的意义何在? @APC 现在是 12c。该函数使用 id 和 seq 查找记录。一个 (id, seq) 对的行中可以有多个记录,这就是为什么有一个循环来连接它们并形成一个字符串。 这个查询会变慢的主要原因是你正在对一个有 5+ 百万行的表进行 FULL TABLE SCAN,并调用一个在游标上循环 50 次的函数。这产生了 2.5 亿次函数调用,无论你如何削减它都会很慢。你可以尝试用NULL; 替换function_abc 的主体,看看循环对你的伤害有多大。祝你好运。 【参考方案1】:

正如所写的那样,标量子查询不会影响性能。函数调用大概是。

您不需要子查询。随便写:

SELECT id, seq,
       function_abc(t.id, t.seq, 115501) as txt_dosage_comments,
       function_abc(t.id, t.seq, 115502) as fld_txt_total_therapy_duration
 . . . 

Oracle 有一个非常聪明的优化器。在这种情况下,它将忽略子查询。

从字段名称来看,该函数正在表中进行某种查找。这肯定会成为更大数据集的性能杀手。

【讨论】:

但这不会丢失scalar subquery caching吗? 编辑: 刚刚注意到 t.idt.seq 是函数调用的一部分,所以我们可以忘记任何缓存... 像这样将我的代码转换为 sn-p 会杀死缓存。 @PrashantMishra 。 . .除非数据中有很多重复项,否则不会进行有用的缓存。【参考方案2】:

不带标量的子查询总是或多或少是一种负担,而且通常发生的情况是这种负担在以后变得不可接受。

一个重要因素是标量函数是否不确定。在提供相同的参数时,确定性函数将始终返回相同的结果。一般来说,任何“选择”都不能确定,因为数据可能会发生变化。如果它是确定性的,则延迟仅限于提供的值的差异。

对于总体上的 SELECT 子查询,最好尝试加入而不是在 select 子句中使用子查询。在大多数情况下,连接是可行的。

【讨论】:

【参考方案3】:

下面是我的问题的答案,并附有详尽的解释: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1594885400346999596

【讨论】:

以上是关于SQL 查询优化:标量子查询是不是会影响性能?的主要内容,如果未能解决你的问题,请参考以下文章

SQL优化:慎用标量子查询,改用left join提升查询效率

SQL为王:oracle标量子查询和表连接改写

T-SQL,在视图中重复相同的标量子查询性能

Oracle优化笔记

彻底搞懂oracle的标量子查询

子查询优化