2009-01-23 97 views
0

希望有人可以对我目前与Oracle数据库有关的问题发表一些看法 - 我确定这很简单!阅读CLOB列很慢

我已经成功的样本中重建这一点,所以这里是数据库结构:

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)中。

很确定这里的网格是不相关的,因为我们通过C++使用开源OTL(不是我的部门,幸运的是)经历了同样的问题。

OK,这个问题....从开始

时间,直到填充网格〜35-40s,哎哟。

但是,如果我做到以下几点:

GRANT SELECT ON MyTable TO TEST_ROLE 
/

,然后再次执行查询时,它需要〜5-6s。

在我看来,这与特权等有关,但我不太确定它为什么仍然实际上两种方式?

只是扔别的东西放入锅中,如果我改变的过程

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

那么时间约5-6s,有或没有额外的SELECT权限。

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

编辑:

操作系统是Vista x86系统业务

Oracle服务器是10.2.0.1

Oracle客户端是10.2.0.3

编辑:

至于建议,我我已经尝试从MS OracleClient更改为ODP.NET,并且按要求加速。

不幸的是,这是受到影响的C#应用​​程序只是其用于查看表/运行存储过程等

我们的主要递送是使用OTL(http://otl.sourceforge.net/otl3_intro.htm),用于访问数据库的C++程序的内部应用程序。这不是真的可以在这个时候改变,所以我真的很想理解差异的原因,而不必无所顾忌地选择GRANT SELECT。

如果缺乏SELECT权限导致完全失败,那么我可能会忍受这一点,但是缺少SELECT似乎会导致访问CLOB数据的一些较慢的路由。

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

P.S.我们真的很想和OCCI一起参与我们的C++,但是由于Oracle在目前我们始终支持IDE的一个版本,所以我们无法让它与我们的Visual Studio 2008良好地配合。

回答

6

您确定你每次都从磁盘读取blob,而不是从磁盘缓存读取第二个和之后的数据?

我在性能测试中看到过这个问题,特别是在Oracle上,第一次运行测试非常糟糕。然后,有一次未成年人(看起来无足轻重的变化)表现突然改善。但真正发生的是,您正在查询的数据已被加载到缓存中,并且可以以10倍或20倍的速率访问(内存与磁盘)。

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

编辑:或者更好:每次删除并重新创建表。你可能会这样做,但没有提到它。

+0

+1;关于缓存的好建议。 – DCookie 2009-01-23 18:26:41

+0

是的,我们在进行性能测试之前就遇到了缓存问题,但这是一个一致的速度问题。即使是第一次使用TO_CLOB(TO_NCLOB())技术的调用也很快,我不希望这会在第一次运行时碰到缓存。谢谢。 – Carl 2009-01-24 07:43:25

1

根据以上建议,您可以尝试不同的ODBC驱动程序或客户端软件。 TO_CLOB(TO_NCLOB())的工作速度如此之快,直接的一个似乎并没有表明问题存在。

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

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

0

我真的认为这里的问题是OTL驱动程序和OracleClient在处理来自SYS_REFCURSOR的CLOB时遇到问题。 SYS_REFCURSORs很弱,这意味着游标本身可以返回任何类型的数据,这意味着驱动程序需要不断返回数据库并查询游标的元数据(即获取游标中的数据类型),然后加载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(),因为这似乎也工作?

+0

不幸的是,返回一个强大的光标并没有什么区别。可以更改存储过程,但是TO_CLOB()本身不起作用 - 它必须是TO_CLOB(TO_NCLOB())。我不确定这些电话实际上做了什么,也就是说,它们有多昂贵? – Carl 2009-01-28 09:46:25

0

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

select * from nls_database_parameters; 

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

这可能会提供一些更深入的问题,并有助于回答TO_CLOB(TO_NCLOB())调用的代价有多昂贵的问题。

0

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

我在Oracle 10g一年左右的clob性能方面遇到了问题。一旦我们获得了令人敬畏的dba的帮助,我们就解决了其中的大部分问题。花了大约2个月的时间才将性能提升到足够的速度。

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

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

另一个解决方法: 如果您发现持久性较慢,或者访问速度缓慢且未绑定CPU,则将数据压缩并将其存储在Blob中。我们在这里也看到了很大的性能优势。

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

我确实怀疑系统表是否可能被分割?有很多表/模式吗?同义词呢?

另外,当你存储clobs时,不要将它们存储到Oracle的一个海量文件中吗?如果我没有记错,你必须小心碎片化;存储不会被释放以供重用。

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