代码之家  ›  专栏  ›  技术社区  ›  Brad Bruce

为什么plsql比sql*plus慢

  •  6
  • Brad Bruce  · 技术社区  · 16 年前

    我有几个Oracle查询在运行SQL*PLUS时性能很好。但是,当它们作为一个pl/sql包的一部分执行时,需要花费更长的时间。

    我们的DBA观察到这些查询通过PLSQL需要10分钟,通过SQL*PLUS需要10秒。

    有没有人对在哪里寻找错误配置有什么建议?

    客户端-Windows 2000 服务器-Linux(Oracle Enterprise)

    谢谢

    ——

    决议:

    我希望我能接受每个人的回答。他们中的一些人很有帮助。

    • 查询正在转换数据类型。
    • 执行计划不匹配。 (提示修正了这一点。)
    • DBA正在查看光标所在的时间。 打开而不是查询时间。
    7 回复  |  直到 14 年前
        1
  •  9
  •   Tony Andrews    16 年前

    使用SQL跟踪查看每种情况下的执行计划。一种可能引起人们的注意(从经验中):包是否将错误类型的值绑定到查询?可能是在SQL Plus中,您正在运行:

    select * from mytable where id = '1234';
    

    但在pl/sql中,您正在运行:

    select * from mytable where id = p_id;
    

    将p_id定义为数字。这将强制ID列上的to_编号,并阻止Oracle使用索引。

        2
  •  3
  •   Quassnoi    16 年前

    最有可能的是,运行时间更长的不是查询,而是处理它们的开销 PL/SQL .

    当处理查询结果时, PL/SQL 脚本,发生上下文切换。它需要在 Oracle 过程非常缓慢。

    像这样的代码:

    DECLARE
            cnt INTEGER := 0;
            CURSOR  cr_main IS
            SELECT  1 AS id
            FROM    dual
            CONNECT BY
                    level <= 1000000;
    BEGIN
            FOR res IN cr_main
            LOOP
                    cnt := cnt + res.id;
            END LOOP;
            DBMS_OUTPUT.put_line(cnt);
    END;
    

    跑步次数超过 3 我机器上的秒数,而这个:

    SELECT  SUM(1)
    FROM    dual
    CONNECT BY
            level <= 1000000
    

    仅完成 0.5 秒。

    当您调用 PL/SQL SQL ,像这样:

    SELECT  plsql_function(column)
    FROM    mytable
    

    或者当触发器触发时。

        3
  •  2
  •   jva    16 年前

    我们的DBA观察到这些查询通过plsql需要10分钟,通过pl/psql需要10秒。

    我可以理解,如果DBA不想为您解决这个问题,但如果您的DBA确实看到了这两种情况,并且还没有为您提供两种情况的解释计划,那么他实际上不是一个非常好的DBA。

    可能没有错误的配置,我自己也经历过——所有绑定变量,没有常量,没有提示。直接运行-性能良好。把它放进去开始…结束-砰,慢得要命。结果发现,有时查询只使用来自pl/sql(即Oracle9.2)中的不同执行计划。

    我的解决方案-使用提示,直到pl/sql版本使用与sql相同的计划。

    其他可能的问题:

    1. SQL*PLUS只返回前100个或 所以行,然后等待您请求更多,但是pl/sql必须处理 他们都不请自来。小问题,但有时被忽视。
    2. 您可以为SQL*PLUS使用常量,为PL/SQL使用绑定变量。有时使用常量允许优化器检查倾斜的数据,并且可以使用其他索引。
        4
  •  1
  •   David Aldridge    16 年前

    你真的像这样比较吗?您是在pl/sql(最佳情况)中执行原始SQL语句,还是使用显式或隐式游标返回值,然后处理它们?有很大的不同。

        5
  •  1
  •   Sebastien Kevin    14 年前

    我们也面临同样的问题。在pl/sql块中使用时,更新查询的运行速度非常慢17分钟,在pl/sql外部使用时,执行速度非常快(不到2秒)。

    我们发现PL/SQL中使用的执行计划是不同的。

    使用“alter-system-flush-shared-pool”为我们解决了这个问题。它似乎迫使PL/SQL重新考虑要使用的执行计划。

        6
  •  0
  •   Brian    16 年前

    引用和扩展quassnoi:

    最有可能的是,运行时间更长的不是查询,而是在pl/sql中处理它们的开销。

    在pl/sql脚本中处理查询结果时,会发生上下文切换。它需要在Oracle进程之间传递数据负载,速度非常慢。

    像这样的代码:

    DECLARE
            cnt INTEGER := 0;
            CURSOR  cr_main IS
            SELECT  1 AS id
            FROM    dual
            CONNECT BY
                    level <= 1000000;
    BEGIN
            FOR res IN cr_main
            LOOP
                    cnt := cnt + res.id;
            END LOOP;
            DBMS_OUTPUT.put_line(cnt);
    END;
    

    在我的计算机上运行超过3秒,而此计算机:

    SELECT  SUM(1)
    FROM    dual
    CONNECT BY
            level <= 1000000
    

    只需0.5秒即可完成。

    当您从SQL调用pl/sql时,也会发生上下文切换,如下所示:

    SELECT  plsql_function(column)
    FROM    mytable
    or when a trigger fires.
    

    解决上下文切换问题的一种方法是使用批量收集。如果要收集大量的行,则在某些类型的集合中使用大容量收集可以极大地加快PL/SQL语句中的SQL。

        7
  •  0
  •   darreljnz    16 年前

    通过sqlplus发布的dml(例如select、update、delete)直接发布到Oracle的SQL引擎,而pl sql过程中的dml首先由pl/sql处理(例如进行变量绑定),然后发送到SQL引擎。

    在大多数情况下,pl/sql中的同一条语句将执行与sql相同的操作,并且这两种方法通常会生成相同的执行计划。根据我的经验(通常需要绑定变量时),这会导致非常不同的性能。我曾经看到过这样的情况:在SQL Plus中发出的select只需要一秒钟的时间,而通过pl/sql发出的select只需要1-2分钟。

    我建议您调整您的语句,以便它在pl/sql中和在sql中一样工作。注意正确绑定变量(使用forall和bulk collect),同时检查执行计划和进行单元测试。