2013-04-16 2 views
1

Ниже приведен запрос, в котором я использую функцию агрегации. Предложение where просто с индексом corpId и incoming_date. Если я просто извлекаю все строки/подсчет, запрос занимает меньше секунды. Однако, когда я использую агрегированную функцию, запрос занимает около 4 минут. Я использую oracle 11i, а полные строки, которые получает запрос where, составляют около 64000. Статистика таблиц и индексов также была собрана недавно, и в таблице не добавлены новые строки.Query Performance при использовании функции агрегации Oracle

Просьба предложить улучшить скорость.

SELECT 
sum(paid_amt) totalamount 
FROM test_table e 
WHERE e.corpId =6 
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy') 
AND e. incoming _date <= to_date('09-01-2013','dd-mm-yyyy') 
+2

Какие два запроса вы используете? В частности, когда вы не используете функцию aggregate, вы выбираете столбец 'paid_amt'? Каковы два плана запросов? Вы говорите, что для возврата последней из 64 000 строк требуется меньше секунды? Или вы используете графический интерфейс, который отображает первые несколько строк, прежде чем извлекать последнюю строку? –

+0

2 запроса: первый из них я уже опубликовал, а второй - тот, который выбирает счетчик (используя count (*)). Счет дает 64k ​​менее чем за секунду, а сумма занимает 4 минуты. – user2194253

ответ

3

Включите paid_amt в индекс:

CREATE INDEX 
     ix_testtable_cord_date_paid 
ON  test_table (corpId, incoming_date, paid_amt) 

Если у вас есть индекс только на (corpId, incoming_date) и попытаться проверить скорость, как это:

SELECT COUNT(*) 
FROM test_table 
WHERE e.corpId = 6 
     AND e.incoming_date >= to_date('01-12-2012','dd-mm-yyyy') 
     AND e.incoming_date <= to_date('09-01-2013','dd-mm-yyyy') 

вы не запрашивая ни за что за пределами чтобы запрос удовлетворялся только INDEX (RANGE SCAN).

Как только вы добавляете что-либо не в индекс (paid_amt в вашем случае), для получения записи из таблицы необходимо использовать дополнительные TABLE ACCESS (BY INDEX ROWID).

Это случайный поиск в вложенном цикле, и он медленный, особенно если ваши записи в таблице большие (у них много полей или длинных полей).

Оптимизатор может даже считать этот метод доступа менее эффективным, чем FULL SCAN, и использовать его вместо этого.

+0

Правда. Благодарю. Я создаю составной индекс на (corpId, incoming_date, paid_amt). Таблица содержит 319 332 896 записей. Таким образом, создание индекса займет некоторое время. Будет опубликовано обновление после создания индекса. – user2194253

+0

Спасибо за ваше предложение. Он работал хорошо. Сумма составляет 0,1 с. Что делать, если я изменил свой запрос на следующий ниже: – user2194253

+0

SELECT NVL (SUM (paid_amt), 0) paidAmount, NVL (SUM (cust_served), 0) totalCustServed, NVL (SUM (BILLED_AMT, 0)) billedAmt, NVL (SUM (e.tax_paid, 0)) taxPaid, COUNT (DISTINCT CUST_NAME) custName, NVL (СУММА (bal_Payment, 0)) balPayment, NVL (СУММА (adv_payment, 0)) advPayment ОТ test_table е ГДЕ 1 = 1 И e.corp_id = 92 И e.incoming_date> = '02 -Aug-2012 ' И e.incoming__date <= '09 -Jan-2013' – user2194253

0

Я воссоздал этот сценарий, как это ...

CREATE TABLE test_table 
    (id integer 
    , corpId integer 
    , paid_amt number(10,2) 
    , incoming_date DATE); 

ALTER TABLE test_table 
add CONSTRAINT test_table_pk PRIMARY KEY (id); 

create index test_table_nui_1 on test_table(corpId); 

create index test_table_nui_2 on test_table(incoming_date); 

create sequence test_table_seq; 

insert into test_table 
    select test_table_seq.nextval 
     ,MOD(test_table_seq.currval,6) 
     ,MOD(test_table_seq.currval,10) + 1 
     ,sysdate - MOD(test_table_seq.currval,200) 
    from all_objects, user_objects; 

Декартово присоединиться между ALL_OBJECTS и USER_OBJECTS просто взломать, чтобы получить загрузку записей вставлено быстро. (657,000 строк в данном случае)

проходит через первый выбирает все 657000 ...

select sum(paid_amt) 
from test_table; 

План ВЫБРАТЬ ЗАЯВЛЕНИЕ ALL_ROWSCost: 621 байт: 13 CARDINALITY: 1
2 SORT СОВОКУПНЫЕ Б 13 CARDINALITY : 1
1 ТАБЛИЦА ACCESS ПОЛНОЙ ТАБЛИЦА DAVE.TEST_TABLE Стоимость: 621 Bytes: 9923914 мощностные: 763.378

Тогда 109,650 за одну corpId ...

select sum(paid_amt) 
from test_table 
where corpId = 5; 

план ЗЕЬЕСТА ALL_ROWSCost: 265 Б: 26 CARDINALITY: 1
3 SORT СОВОКУПНЫЕ Б: 26 CARDINALITY: 1
2 Таблицы ДОСТУП ROWID индексной Таблица DAVE.TEST_TABLE Стоимость: 265 Б: 3310138 Кардинальность: 127313
1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_1 Стоимость: 213 Cardinality: 3054

И, наконец, 20836 строк ограничивающих по дате ...

SELECT sum(paid_amt) totalamount 
FROM test_table e 
WHERE e.corpId = 5 
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy') 
AND e. incoming_date <= to_date('09-01-2013','dd-mm-yyyy') 

план ЗЕЬЕСТА ALL_ROWSCost: 265 Б: 35 CARDINALITY: 1
3 SORT СОВОКУПНЫЕ Б: 35 CARDINALITY: 1
2 Таблицы ДОСТУП ROWID индексной Таблица DAVE.TEST_TABLE Стоимость: 265 Б 871360 CARDINALITY : 24896
1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_1 Стоимость: 213 Cardinality: 3,054

Все 3 запросы были быстрые (т.е. < 0,5 секунды)

Альтернативой было бы сбросить nui_1 и nui_2 и создать объединенный индекс для обоих столбцов. Это побежал в 31ms на моем дб

create index test_table_nui_3 on test_table(corpId, incoming_date); 

План оператора SELECT ALL_ROWSCost: 15 Б: 35 мощностные: 1
3 SORT СОВОКУПНЫЕ Б: 35 мощностные: 1
2 ТАБЛИЦА ACCESS BY INDEX ROWID TABLE DAVE. test_table Стоимость: 15 Б: 871360 мощностные: 24896
1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_3 Стоимость: 3 Cardinality: 14

Это говорит о том, что совокупная функция не проблема, но ваша индексация может быть. Лучше всего было бы проверить ваши планы объяснений.

+0

У меня уже есть составной индекс (corpId, incoming_date). Проблема состоит в том, что test_table имеет 319 332 896 записей. Предложение where, которое я указал, извлекает записи 64k (используется счетчик (*)), который является быстрым (менее секунды) из-за составного индекса. Вычисление суммы (paid_amt) для этих 64k записей занимает много времени. – user2194253

+0

Извините, не понял, что стол был таким большим. – Dave

+0

Вы можете рассмотреть разбиение на corp_id и/или дату, или вы можете использовать материализованное представление. MV снизил мой пример до 15 мс даже после того, как я удвоил количество строк. – Dave