Pro*c различия в производительности
-
26-10-2019 - |
Вопрос
Я бегу в следующем сценарии, который дает мне немного головных болей, так как я не могу найти точного объяснения поведения, которое я вижу. У меня следующее объявлено:
struct test_struct
{
long testv1;
char testv2[51];
long testv3;
};
и соответствующая таблица в Oracle 10G:
CREATE TABLE test_table
(
testv1 NUMBER(10, 0),
testv2 VARCHAR(50),
testv3 NUMBER(4, 0)
);
Чтобы получить доступ к данным в этой таблице, у меня есть функция:
bool getTestData(long test_var1, struct test_struct *outStruct)
И здесь я вижу различия, которые мне нужно объяснить, но не могу. Если тело функции выглядит так:
EXEC SQL BEGIN DECLARE SECTION;
long testvar1_param = test_var1;
struct test_struct *resStruct = outStruct;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT testv1, testv2, testv3
INTO :resStruct
FROM test_table
WHERE testv1 = :testvar1_param;
Я получаю более медленную производительность, тогда если тело функции выглядит как:
EXEC SQL BEGIN DECLARE SECTION;
long testvar1_param = test_var1;
long *testv1_res = &(outStruct->testv1);
char *testv2_res = outStruct->testv2;
long *testv3_res = &(outStruct->testv3);
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT testv1, testv2, testv3
INTO :testv1_res, :testv2_res, :testv3_res
FROM test_table
WHERE testv1 = :testvar1_param;
Производительность во втором отличается значительным отрывом.
Кто -нибудь знает, что может объяснить это поведение?
Решение
Для проблем с производительностью, которые выглядят необъяснимыми с первого взгляда: включите отслеживание SQL, включая ожидание.
ALTER SESSION SET TRACEFILE_IDENTIFIER = "some_unique_identifier";
dbms_support.start_trace (binds=>true,waits=>true);
Запустите свой код, сделайте его совершение и отключите изящно. Не используйте dbms_support.stop_trace, потому что это может предотвратить катушки операций Rowsource. В сгенерированном Tracefile вы найдете точный текст SQL по мере его проанализирования, события ожидания, которые повлияли на SQL и операции Rowsource. Операции Rowsource показывают, как именно выглядит план SQL во время работы SQL.
- Проверьте количество анализа
- Проверьте, что используются переменные привязки или нет.
- Проверьте операции Rowsource для ожидаемого плана.
Для вашей проблемы - необходимость приносить множество рядов случайным образом - я ожидаю найти
- 1 Декларация курсора
- 1 Parse
- петля, которая открывает/извлекает/закрывает курсор
Для этих сценариев очень важно не анализировать каждый выбор. Растановление может занять больше времени, чем исполнение.
Один вопрос, который остается: зачем получать все ряды один за другим? Это какая -то операция копирования данных?
Другие советы
Вы учитываете эффект кэширования? Я предполагаю, что нет.
Если вы запустите первый запрос, запустите второй запрос, где значение testvar1_param одинаково, второе завершается в заметно другое время. Не имеет значения, какой запрос запускается первым, вторая версия будет лучше.
Это связано с тем, что место, где предикат одинаково в обоих запросах, а данные в результатах одинаковы в обоих запросах. Обычно последующие запросы идентичные запросы работают намного быстрее, когда вы идете против индексированного запроса, потому что вы никогда не заходите к таблице, чтобы получить результат, он исходит от SGA, где он кэширован.
Попробуйте использовать разные значения для TestVAR1_PARAM и запустите 10 запросов каждого из них с совершенно разными значениями PARM. Они будут очень близки вовремя.
Вы используете tkprof, верно?
Я имею в виду время (так как это развитие, верно?)
ALTER SYSTEM SET TIMED_STATISTICS = TRUE;
Это улучшает то, что Oracle дает вам в отслеживании для производительности.