0

希望有人能对我目前在使用 Oracle DB 时遇到的问题有所了解——我相信这很简单!

我已经设法在示例中重新创建了它,所以这里是数据库结构:

CREATE TABLE MyTable(
    ixMyTable NUMBER,
    clobData CLOB
)
/

CREATE OR REPLACE PACKAGE PKGTEST
AS
    PROCEDURE DoSomething(
        cur_OUT OUT SYS_REFCURSOR
        );
END PKGTEST;
/

CREATE OR REPLACE PACKAGE BODY PKGTEST
AS

PROCEDURE DoSomething(
    cur_OUT OUT SYS_REFCURSOR
)
AS
BEGIN
    OPEN cur_OUT FOR 
        SELECT ixMyTable, clobData
        FROM MyTable;
END;

END PKGTEST;
/

GRANT EXECUTE ON PKGTEST TO TEST_ROLE
/

BEGIN
    FOR i IN 1 .. 7000 LOOP
        insert into mytable values (i, TO_CLOB('123456'));
    END LOOP;
END;
/

额外信息:

架构所有者是 TEST_SCHEMA

用户是 CARL

CARL 具有 TEST_ROLE 角色

鉴于上述数据库设置,我有一个 C# 测试应用程序,它使用标准 System.Data.OracleClient.OracleCommand 等来执行 PKGTEST.DoSomething 并将结果放入数据网格(DevExpress)。

很确定网格在这里无关紧要,因为我们通过使用开源 OTL 的 c++ 遇到了同样的问题(幸运的是,不是我的部门)。

好的,解决问题....

从开始到填充网格的时间约为 35-40 秒,哎哟。

但是,如果我执行以下操作:

GRANT SELECT ON MyTable TO TEST_ROLE
/

然后再次执行查询,大约需要 5-6 秒。

在我看来,这与特权等有关,但我不太确定为什么它实际上仍然可以双向工作?

只是把别的东西扔进锅里,如果我把程序改成

SELECT ixMyTable, TO_CLOB(TO_NCLOB(clobData))
FROM MyTable;

然后时间约为 5-6 秒,有或没有额外的 SELECT 权限。

任何指针或直接的解决方案将不胜感激!

编辑:

操作系统是 Vista x86 Business

Oracle 服务器是 10.2.0.1

Oracle 客户端是 10.2.0.3

编辑:

正如建议的那样,我尝试从 MS OracleClient 更改为 ODP.NET,这确实可以根据需要加快速度。

不幸的是,受影响的 C# 应用程序只是一个用于查看表/运行 SPROCS 等的内部应用程序。

我们的主要交付物是使用 OTL ( http://otl.sourceforge.net/otl3_intro.htm ) 进行数据库访问的 C++ 应用程序。目前这不是真的可以改变的东西,所以我真的很想了解造成这种差异的原因,而不必无缘无故地抛出无缘无故的 GRANT SELECTs。

如果缺少 SELECT 权限导致完全失败,那么我可能会忍受这种情况,但缺少 SELECT 似乎会导致访问 CLOB 数据的路径变慢。

我已经标记了 3 个答案 - 谢谢那些 - 但我真的可以有一个理由,所以我会为此添加一个赏金。

PS 我们真的很想在一开始就为我们的 C++ 使用 OCCI,但是由于 Oracle 一直支持在当前版本之前的 IDE,我们无法让它与我们的 Visual Studio 2008 很好地配合使用。

4

7 回答 7

7

您确定每次都从磁盘读取 blob,而不是从磁盘缓存中读取第二次及以下吗?

我已经在性能测试中看到了这个问题,特别是在 Oracle 上,第一次运行测试很糟糕。然后通过一个微小的(并且看似微不足道的变化),性能突然显着提高。但实际上发生的情况是,您正在查询的数据已加载到缓存中,并且可以以 10 倍或 20 倍的速率访问(内存与磁盘)。

进行此测试的正确方法是在查询运行之间反弹数据库。如果 DBA 不允许您为该测试反弹测试生产服务器,请在您的机器上加载 Oracle XE 的副本。

编辑:或者更好:每次都删除并重新创建表。您可能正在这样做,但没有提及。

于 2009-01-23T18:04:39.350 回答
1

我会尝试 odp.net http://www.oracle.com/technology/tech/windows/odpnet/index.html而不是 System.Data.OracleClient。

于 2009-01-23T19:44:32.423 回答
1

按照上面的建议,您可以尝试不同的 ODBC 驱动程序或客户端软件。工作速度如此之快的事实TO_CLOB(TO_NCLOB())似乎并不表明这就是问题所在。

首先,我将获取这两个查询并通过 SQLDeveloper 运行它们并获得一个解释计划。这应该为您提供在 Oracle 端执行的基线。添加转换对执行路径应该没有影响。交替运行查询并计时以查看它们的速度。如果没有区别,我建议客户端软件是您的问题。

如果我的假设是正确的,这也可以解释这种GRANT SELECT变化。客户端软件正在 CLOB 上进行某种昂贵的转换。授权和/或显式转换允许客户端避免这种情况。我不知道为什么。

于 2009-01-24T13:37:11.760 回答
1

我知道这是一个很老的问题

我从我使用 Oracle OCCI 库的经验谈起,但我相信这将适用于任何 Oracle 客户端。blob/clob 读取操作慢的原因如下

  1. 从具有 blob/clob 列的表中进行选择可防止预取。您可以在 sqlplus 中通过对带有 & 不带 blob/clob 列的表使用set arraysize 1&来试验这一点。set arraysize 5000对于具有大量记录且没有 blob/clob 列的表,arraysize会有很大的不同。对于具有 blob/clob 列的表,它不会有太大的区别。因此读取每条记录都会往返于服务器。在较慢的网络(例如 WAN)上,这会产生很大的影响
  2. 获取 blob/clob 列需要分别获取定位器和数据。所以这是到服务器的 2 次往返。现在将它与#1 结合起来,你可以看到为什么它很慢

看这里。 https://docs.oracle.com/cd/E18283_01/appdev.112/e10646/oci07lob.htm#CHDDHFAB

您可以通过为 LOB 启用行预取来缓解这种情况。 https://docs.oracle.com/en/database/oracle/oracle-database/12.2/jajdb/index.html?oracle/jdbc/OracleStatement.html

我从来没有让这个为 OCCI 工作,但实现了这里提到的解决方法(Is there a way to prefetch LOBs data in occi?

于 2021-02-07T09:20:06.877 回答
0

老实说,我认为这里的问题是 OTL 驱动程序和 OracleClient 在处理来自 SYS_REFCURSOR 的 CLOB 时遇到问题。SYS_REFCURSOR 很弱,这意味着游标本身可以返回任何类型的数据,这意味着驱动程序需要不断返回数据库并查询游标的元数据(即获取游标中的数据类型),然后加载 CLOB 流,然后加载数据。显然,如果执行查询的用户可以访问被查询的表,驱动程序可以更好地检索元数据并返回正确的数据。

更改存储过程以返回强大的 ref_cursor 是否有效?

CREATE OR REPLACE PACKAGE PKGTEST
    AS
    TYPE C_DoSomething IS REF CURSOR RETURN MyTable%ROWTYPE;
    PROCEDURE DoSomething(
        cur_OUT OUT c_DoSomething
     );
END PKGTEST;

你能改变存储过程来做TO_CLOB(),因为这似乎也有效吗?

于 2009-01-27T17:45:08.410 回答
0

您的数据库的 NLS_CHARACTERSET 和 NLS_NCHAR_CHARACTERSET 是什么。跑

select * from nls_database_parameters;

得到结果。您的客户端软件的 NLS_LANG 设置是什么?

这可能会更深入地了解该问题,并有助于回答 TO_CLOB(TO_NCLOB()) 调用有多昂贵的问题。

于 2009-01-30T15:53:37.067 回答
0

这些不一定都直接相关,但您可能应该检查每一个以防万一。我怀疑这与缓存有关:一旦你完成了第一个查询,然后应用 select,它就会快速运行。如果你想正确地进行性能测试,你必须在中间反弹服务器以摆脱缓存。如果您执行此测试并且它突然表现更好,则尝试将表固定到缓存中。请参阅下面的内联 clob 存储,因为这可能是相关的。

大约一年前,我在 Oracle 10g 中遇到了有关 clob 性能的问题。一旦我们得到了很棒的 dba 的帮助,我们就绕过了他们中的大多数。大约需要 2 个月的时间才能使性能达到足够的速度。

您使用的是哪个版本的 Oracle?在 Oracle 10g(早期版本)中,clob 性能存在大量问题。事实上,在某些情况下,只使用两个表和一个 varchar 列实际上更快(将 varchar 连接在一起,你就有了你的 clob)。我们升级到更高版本,它好多了

另外,您的数据存储在哪里?还有一个选项可以将 clob 存储在表本身中。根据您的数据有多大,您可能会发现这有助于提高性能。如果您将数据存储在 SAN 上,那么还值得查看 SAN 上的缓存大小以及块大小。当缓存大小不正确时,Oracle + SAN 可能会有点有趣。

另一种解决方法:如果您发现持久性很慢,甚至访问很慢,并且您不受 CPU 限制,请压缩数据并将其存储在一个 blob 中。我们在这里也看到了巨大的性能优势。

如果您在处理 clob 的过程中发现性能问题(与内存相关?),我们发现我们会将对象重新创建为新字符串。即使数据较小,驱动程序也会预先创建 32K 大小的字符串。

我确实想知道系统表是否可能是碎片化的?有很多表/模式吗?同义词呢?

另外,当您存储 clob 时,它们不会存储到 Oracle 中的一个大文件中吗?如果我没记错的话,您必须小心碎片化;存储不会被释放以供重复使用。

也许您可以在您的数据库前面放置一个 .NET Web 服务?如果您无法解决性能问题,这可能是一种选择。

于 2009-01-31T12:25:00.513 回答