2014-01-08 4 views
-1

Я относительный новый для sql, и у меня есть инструкция, которая вечно запускается.Oracle sql statement на очень большой таблице

SELECT 
    sum(a.amountcur) 
FROM 
    custtrans a 
WHERE 
    a.transdate <= '2013-12-31'; 

Я большой стол, но statemnt занимает около 6 минут! Любые идеи, почему?

+1

Опубликовать объяснение плана того же. Он дает больше света. – SriniV

+6

1. Определите навсегда. Это секунды, минуты, часы? 2. Не ретранслируйте неявное преобразование типов данных, когда-либо. В вашей ситуации используйте функцию 'to_date()', чтобы преобразовать буквенный символ символа, представляющий дату, в значение типа данных data. поэтому ваш предикат может выглядеть так: 'где a.transdate <= to_date ('2013-12-31', 'yyyy-mm-dd')' или 'where a.transdate <= date '2013-12-31' '. Кроме того, всегда полезно предоставить немного больше информации о том, насколько велика ваша таблица, каков план выполнения, есть ли какие-либо индексы и т. Д. –

+0

@NicholasKrasnov Вы читали мой разум :) – SriniV

ответ

1

Удостоверьтесь, что таблица имеет индекс на трансдате.

create index custtrans_idx on custtrans (transdate); 

Кроме того, если это поле определено как дата в таблице затем сделать

SELECT sum(a.amountcur) 
    FROM custtrans a 
    WHERE a.transdate <= to_date('2013-12-31', 'yyyy-mm-dd'); 
+1

Когда он выбирает «все до недели назад», этот индекс может повредить больше, чем помогает, потому что запрос все равно будет читать 99% таблицы данных и индекс сверху. –

+0

Это неверное утверждение. Oracle будет читать индекс b-tree (скорость log n^n), получая только соответствующие строки и затем доступ к таблице. –

+0

Сказав это, ваше сообщение с индексированием обоих столбцов лучше, потому что оракул может выполнять только сканирование индекса. –

1

Если таблица действительно большой, то запрос должен сканировать каждую строку с transdate ниже дано.

Даже если у вас есть указатель на transdate, и он помогает остановить сканирование раньше (это может быть не так), когда количество совпадающих строк очень велико, для их сканирования потребуется много времени и суммирования значений ,

Чтобы ускорить процесс, вы можете рассчитать частичные суммы, например. за каждый прошедший месяц, считая, что ваши данные исторические, а прошлое не меняется. Тогда вам нужно будет только сканировать custtrans только на 1-2 месяца, затем быстро сканировать таблицу ежемесячными суммами и добавлять результаты.

0

Одним из вариантов является создание индекса в столбце, используемом в предложении where (это полезно, если вы хотите получить только 10-15% строк, используя индексированный столбец).

Другой вариант заключается в разделении таблицы, если она содержит миллионы строк. В этом случае, если вы попытаетесь получить 70-80% данных, это не поможет.

Лучший вариант - сначала проанализировать ваши требования, а затем сделать выбор.

Всякий раз, когда вы занимаетесь функциями даты, лучше использовать функцию to_date(). Не полагайтесь на неявное преобразование типа данных.

+0

Что такое «таблица ur» или «сделка u»? –

+0

Если вы выберете, скажем, 90% всех табличных данных, то разделение ничего не изменит с точки зрения производительности. –

+0

-1 .. Первая вещь никогда не должна состоять в том, чтобы просто создать индекс. Прежде всего, чтобы получить ПУТЬ больше информации. Вы должны понимать, где идет время, количество данных, которые необходимо отсканировать, чтобы получить результат, и как эти данные находятся в таблице (индексы полезны для исключения посещений блоков.% Строк сравнительно не имеет значения) – Craig

2

Ваш выбор, когда вы публикуете его, будет читать 99% всей таблицы (2013-12-31 всего лишь неделю назад, и я предполагаю, что большинство записей до этой даты и только очень немного после). Если в вашей таблице много больших столбцов (например, varchar2 (4000)), все эти данные также будут прочитаны, когда оракул сканирует таблицу. Таким образом, вы можете прочитать несколько килобайт каждой строки, чтобы получить 30 байтов, которые вам нужны для суммы и трансляции.

Если у вас есть этот сценарий. создать комбинированный индекс transdate и amountcur:

CREATE INDEX myindex ON custtrans(transdate, amountcur) 

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

+0

LOBS хранятся вне фактической таблицы по умолчанию. Поэтому, если вы не выберите какой-либо столбец LOB, они не будут прочитаны с диска. –

+0

@Wernfried: Правильно, спасибо. Исправил мой пост. –

+0

plus 1 - это самый эффективный и быстрый индекс. Не следует прикасаться к базовой таблице. Единственный возможный быстрый способ сделать это - разбить индекс. –

0

Попробуйте создать индекс только на колонке amountcur:

CREATE INDEX myindex ON custtrans(amountcur) 

В этом случае Oracle будет читать, скорее всего, только индекс (Index Full Scan), больше ничего.

Коррекция, как указано в комментарии.Она должна быть составной индекс:

CREATE INDEX myindex ON custtrans(transdate, amountcur) 

Но может быть, это немного бесполезный для создания индекса только для одного оператора выбора.

+0

Oracle все равно придется читать запрос, чтобы удовлетворить предложение WHERE, поскольку transdate не находится в вашем индексе. – Craig

+0

Да, вы правы. В этом случае он должен быть составным индексом. Я изменю свой пост –

Смежные вопросы