Чтение столбца CLOB идет медленно - PullRequest
0 голосов
/ 23 января 2009

Надеюсь, кто-то может пролить немного света на проблему, которая у меня сейчас есть с БД Oracle - я уверен, что это что-то простое !!

Мне удалось воссоздать это в примере, поэтому вот структура БД:

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-6 с.

Мне кажется, что это как-то связано с привилегиями и т. Д., Но я не совсем уверен, почему это все-таки работает в обоих направлениях ??

Просто бросить что-то еще в банк, если я изменю процедуру на

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

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

Будем весьма благодарны за любые указатели или прямые решения!

Edit:

ОС - это Vista x86 Business

Сервер Oracle: 10.2.0.1

Клиент Oracle - 10.2.0.3

Edit:

Как и предполагалось, я попытался перейти с MS OracleClient на ODP.NET, и это ускоряется по мере необходимости.

К сожалению, уязвимое приложение C # было только внутренним приложением, которое используется для просмотра таблиц / запуска SPROCS и т. Д.

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

Если отсутствие привилегии SELECT вызвало полный сбой, то, вероятно, я мог бы с этим смириться, но отсутствие SELECT, по-видимому, вызывает более медленный маршрут для доступа к данным CLOB.

Я пометил 3 ответа - спасибо за них - но я действительно мог бы объяснить причину, поэтому я добавлю награду к этому.

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

Ответы [ 6 ]

6 голосов
/ 23 января 2009

Вы уверены, что каждый раз читаете большой двоичный объект с диска, а не читаете, если из дискового кэша второй и следующий?

Я видел эту проблему с тестированием производительности, особенно в Oracle, где первый запуск теста ужасен. Затем с одним незначительным (и кажущимся незначительным изменением) производительность неожиданно значительно улучшается. Но на самом деле произошло то, что запрашиваемые вами данные были загружены в кэш и могут иметь доступ в 10 или 20 раз быстрее (память или диск).

Правильный способ сделать этот тест - сбросить базу данных между запусками запросов. Загрузите копию Oracle XE на свой компьютер, если администратор БД не позволит вам отскочить от тестового рабочего сервера для этого теста.

Редактировать: Или лучше: отбрасывать и заново создавать таблицу каждый раз. Возможно, вы делаете это, но не упоминали об этом.

1 голос
/ 24 января 2009

Следуя приведенному выше предложению, вы можете попробовать другой драйвер ODBC или клиентское программное обеспечение. Тот факт, что TO_CLOB(TO_NCLOB()) работает так быстро, где прямое не кажется, указывает на то, что именно здесь существует проблема.

Сначала я бы взял два запроса и провел их через SQLDeveloper и получил план объяснения. Это должно дать вам основу для исполнения на стороне Oracle. Добавление преобразований не должно иметь никакого значения на пути выполнения. Запускайте запросы поочередно и время, чтобы увидеть, насколько они быстры. Если нет никакой разницы, я бы предположил, что клиентская программа - это ваша проблема.

Если мое предположение верно, это также объясняет изменение GRANT SELECT. Клиентское программное обеспечение выполняет дорогостоящее преобразование в CLOB. Предоставление и / или явное преобразование позволяет клиенту избежать этого. Я не знаю почему.

1 голос
/ 23 января 2009

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

0 голосов
/ 31 января 2009

Они не обязательно связаны напрямую, но вы, вероятно, должны проверить каждый из них на случай, если он связан. Я подозреваю, что это связано с кэшированием: после того, как вы выполнили первый запрос, вы применяете select, а затем все идет быстро. В середине вы должны отскочить от сервера, чтобы избавиться от кешей, если вы хотите правильно протестировать производительность. Если вы выполните этот тест, и он внезапно начнет работать лучше, попробуйте закрепить таблицу в кеше. См. Ниже о встроенном хранилище Clob, поскольку это, вероятно, будет связано.

У меня были проблемы с производительностью клоба в Oracle 10g год назад. Мы обошли большинство из них, как только получили наш удивительный дба, чтобы помочь. Потребовалось около 2 месяцев, чтобы довести производительность до адекватной скорости.

Какую версию Oracle вы используете? В Oracle 10g (ранние версии) были серьезные проблемы с производительностью клобов. На самом деле в некоторых случаях было проще использовать две таблицы и столбец varchar (объедините varchars вместе, и у вас будет ваш клоб). Мы обновились до более поздней версии, и она стала намного лучше

Кроме того, где хранятся ваши данные? Также есть возможность хранить сгусток в самой таблице. В зависимости от размера ваших данных, это может повысить производительность. Если ваши данные хранятся в SAN, то стоит также посмотреть на размер кэша в SAN, а также размеры блоков. Oracle + SAN может быть немного забавным, когда размеры кэширования неправильные.

Другой обходной путь: Если вы обнаружите, что постоянство медленное или даже доступ медленный, и вы не привязаны к процессору, архивируйте данные и сохраняйте их в виде большого двоичного объекта. Мы также увидели здесь большой выигрыш в производительности.

Если вы видите проблемы с производительностью (связанные с памятью?) При обработке сгустков, мы обнаружили, что мы воссоздаем объекты в виде новых строк. Драйверы предварительно создавали строки размером 32K, даже если данные были меньше.

Мне было интересно, могут ли системные таблицы быть фрагментированными? Много ли таблиц / схем? А как насчет синонимов?

Кроме того, когда вы храните сгустки, они не сохраняются в одном массивном файле в Oracle? Если я правильно помню, вы должны быть осторожны с фрагментацией; хранилище не освобождается для повторного использования.

Возможно, вы могли бы поставить веб-сервис .NET перед вашей БД? Это может быть одним из вариантов, если вы не можете решить проблемы с производительностью.

0 голосов
/ 30 января 2009

Что такое NLS_CHARACTERSET и NLS_NCHAR_CHARACTERSET для вашей базы данных. Выполнить

select * from nls_database_parameters;

, чтобы получить результаты. А что такое настройка NLS_LANG для вашего клиентского программного обеспечения?

Это может дать более глубокое понимание проблемы и поможет ответить на вопрос, насколько дорогой вызов TO_CLOB (TO_NCLOB ()).

0 голосов
/ 27 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...