Четенето на CLOB колона е бавно

Надяваме се, че някой може да хвърли малко светлина върху проблем, който в момента имам с Oracle DB - сигурен съм, че е нещо просто!!

Успях да пресъздам това в проба, така че ето структурата на 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).

Почти съм сигурен, че мрежата е без значение тук, тъй като изпитваме същия проблем чрез c++, използвайки OTL с отворен код (не е моят отдел, за щастие).

Добре, към проблема....

Времето от началото до запълването на мрежата е ~35-40 секунди, ох.

Ако обаче направя следното:

GRANT SELECT ON MyTable TO TEST_ROLE
/

и след това изпълнете заявката отново, отнема ~5-6s.

Струва ми се, че това има нещо общо с привилегии и т.н., но не съм съвсем сигурен защо все още всъщност работи и в двете посоки??

Просто да хвърля нещо друго в тенджерата, ако променя процедурата на

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

Тогава времето е ~5-6s, със или без допълнителната привилегия SELECT.

Всякакви насоки или директни решения ще бъдат много оценени!

Редактиране:

Операционната система е Vista x86 Business

Oracle Server е 10.2.0.1

Oracle Client е 10.2.0.3

Редактиране:

Както беше предложено, опитах се да променя от MS OracleClient към ODP.NET и това ускорява според изискванията.

За съжаление приложението на C#, което беше засегнато, беше само вътрешно приложение, което се използва за преглед на таблици / изпълнение на SPROCS и т.н.

Нашият основен продукт е приложението C++, което използва OTL (http://otl.sourceforge.net/otl3_intro.htm) за достъп до база данни. Това всъщност не е нещо, което може да се промени в момента и затова наистина бих искал да разбера причините за разликата, без да се налага да хвърлям безвъзмездни GRANT SELECTs насам-натам.

Ако липсата на SELECT привилегия причини пълен провал, тогава вероятно бих могъл да се справя с това, но липсата на SELECT изглежда причинява по-бавен маршрут за достъп до CLOB данните.

Отбелязах 3-те отговора - благодаря за тях - но наистина мога да се справя с причина, така че ще добавя премия към това.

P.S. Наистина искахме да използваме OCCI в самото начало за нашия C++, но тъй като Oracle винаги поддържа версия на IDE преди текущата, не успяхме да я накараме да работи добре с нашето Visual Studio 2008.


person Carl    schedule 23.01.2009    source източник


Отговори (7)


Сигурни ли сте, че четете петното от диска всеки път и не четете втория и следващите от дисковия кеш?

Виждал съм този проблем при тестване на производителността, особено на Oracle, където първото изпълнение на тест е ужасно. След това с една незначителна (и привидно незначителна промяна) ефективността изведнъж се подобрява значително. Но наистина това, което се е случило, е, че данните, които питате, са били заредени в кеша и могат да бъдат достъпни с 10x или 20x скорост (памет срещу диск).

Правилният начин да направите този тест е да прехвърляте базата данни между изпълненията на заявката. Заредете копие на Oracle XE на вашата машина, ако DBA не ви позволи да отхвърлите тестовия производствен сървър за този тест.

Редактиране: Или по-добре: пуснете и създавайте отново таблицата всеки път. Може да правите това, но не сте го споменали.

person Thomas Jones-Low    schedule 23.01.2009
comment
Да, и преди сме имали проблеми с кеша, когато сме тествали производителността, но това е постоянен проблем със скоростта. Дори първото извикване с помощта на техниката TO_CLOB(TO_NCLOB()) е бързо и не бих очаквал това да удари кеша при първото изпълнение. Благодаря. - person Carl; 24.01.2009

Бих пробвал odp.net http://www.oracle.com/technology/tech/windows/odpnet/index.html вместо System.Data.OracleClient.

person tuinstoel    schedule 23.01.2009

Следвайки предложението по-горе, можете ли да опитате различен ODBC драйвер или клиентски софтуер. Фактът, че TO_CLOB(TO_NCLOB()) работи толкова по-бързо, когато правият не изглежда показва, че проблемът е там.

Първо ще взема двете заявки и ще ги пусна през SQLDeveloper и ще получа план за обяснение. Това трябва да ви даде базова линия за изпълнение от страна на Oracle. Добавянето на реализациите не би трябвало да има значение за пътя на изпълнение. Изпълнявайте заявките последователно и измервайте времето и на двете, за да видите колко бързи са. Ако няма разлика, предполагам, че клиентският софтуер е вашият проблем.

Ако предположението ми е правилно, това също би обяснило промяната GRANT SELECT. Клиентският софтуер извършва някакво скъпо преобразуване на CLOB. Предоставянето и/или изричното преобразуване позволява на клиента да избегне това. Не знам защо.

person Thomas Jones-Low    schedule 24.01.2009

Знам, че това е наистина стар въпрос

Говоря от моя опит с библиотеката Oracle OCCI, но вярвам, че това ще се отнася за всеки клиент на Oracle. Причините, поради които операциите за четене на blob/clob са бавни, са следните

  1. Изборът от таблици с колони blob/clob предотвратява предварителното извличане. Можете да експериментирате с това в sqlplus, като използвате set arraysize 1 & set arraysize 5000 за таблици с и без колони blob/clob. За таблица с голям брой записи и без колони 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, но внедрих заобиколно решение, споменато тук (Има ли начин за предварително извличане на LOB данни в occi?)

person zrb    schedule 07.02.2021

Честно казано мисля, че проблемът тук е, че OTL драйверът и OracleClient имат проблеми при справянето с CLOB, идващ от SYS_REFCURSOR. 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(), тъй като това също изглежда работи?

person Thomas Jones-Low    schedule 27.01.2009
comment
Връщането на силен курсор не направи разлика, за съжаление. Би било възможно да промените съхранената процедура, но TO_CLOB() сама по себе си не работи - трябва да бъде TO_CLOB(TO_NCLOB()). Не съм сигурен какво всъщност правят тези обаждания, тоест колко скъпи са? - person Carl; 28.01.2009
comment
Цената на TO_CLOB(TO_NCLOB()) зависи от набора от знаци на вашата база данни. Какви са стойностите NLS_CHARACTERSET и NLS_NCHAR_CHARACTERSET от следната заявка? изберете * от nls_database_parameters; - person Thomas Jones-Low; 30.01.2009

Какво представляват NLS_CHARACTERSET и NLS_NCHAR_CHARACTERSET за вашата база данни. Бягай

select * from nls_database_parameters;

за да получите резултатите. И каква е настройката NLS_LANG за вашия клиентски софтуер?

Това може да даде повече представа за проблема и ще помогне да се отговори на въпроса колко скъпо е повикването TO_CLOB(TO_NCLOB()).

person Thomas Jones-Low    schedule 30.01.2009
comment
NLS_CHARACTERSET е AL32UTF8, а NLS_NCHAR_CHARACTERSET е AL16UTF16 - вярвам, че това са настройките по подразбиране за инсталиране на сървър, базиран на Win. Дори не съм сигурен дали/как можете да промените NLS_LANG за нещата на ADO.NET - person Carl; 02.02.2009
comment
to_NCLOB() преобразува в UTF-16 символния набор, след което TO_CLOB() го преобразува обратно в UTF-8 символния набор. Така че обажданията няма да имат голямо влияние върху производителността. Все още нямам добра причина защо, но ако работи... - person Thomas Jones-Low; 03.02.2009

Не всички те са непременно пряко свързани, но вероятно трябва да проверите всеки от тях, в случай че е свързан. Подозирам, че това е свързано с кеширането: след като направите първата си заявка, след това прилагате select и след това става бързо. По средата трябва да отскочите сървъра, за да се отървете от кеш паметта, ако искате да го тествате правилно за производителност. Ако направите този тест и той изведнъж се представи по-добре, опитайте да закачите таблицата в кеша. Вижте по-долу за вграденото съхранение на clob, тъй като това вероятно ще бъде свързано.

Имах проблеми с производителността на clob в Oracle 10g преди година или нещо повече. Заобиколихме повечето от тях, след като получихме нашия страхотен dba на помощ. Отне около 2 месеца, за да достигне адекватна скорост.

Коя версия на Oracle използвате? В Oracle 10g (ранни версии) имаше огромни проблеми с производителността на clob. Всъщност в някои случаи беше по-бързо просто да се използват две таблици и колона varchar (свържете varchar заедно и имате своя clob). Надградихме до по-късна версия и беше много по-добра

Освен това къде се съхраняват вашите данни? Има и опция за съхранение на бучката в самата маса. В зависимост от това колко големи са вашите данни, може да откриете, че това помага за производителността. Ако вашите данни са съхранени в SAN, тогава си струва да погледнете и размера на кеша в SAN, както и размерите на блоковете. Oracle + SAN може да бъде малко смешно, когато размерите на кеширането са неправилни.

Друго решение: Ако установите, че постоянството е бавно или дори достъпът е бавен и не сте обвързани с процесора, компресирайте данните и ги съхранете в blob. Видяхме голяма полза от производителността и тук.

Ако виждате проблеми с производителността (свързани с паметта?) във всичко, което обработва clobs, открихме, че ще пресъздадем обектите като нови низове. Драйверите предварително създаваха низове с размер 32K, дори ако данните бяха по-малки.

Чудех се дали системните таблици може да са фрагментирани? Има ли много таблици/схеми? Какво ще кажете за синонимите?

Освен това, когато съхранявате clobs, те не се ли съхраняват в един масивен файл в Oracle? Ако си спомням правилно, трябва да внимавате за фрагментацията; хранилището не се освобождава за повторна употреба.

Може би бихте могли да поставите .NET уеб услуга пред вашата база данни? Това може да е една от опциите, ако не можете да решите проблемите с производителността.

person Egwor    schedule 31.01.2009