Как сократить время выполнения следующего запроса в Oracle? - PullRequest
0 голосов
/ 27 марта 2012

Я написал следующий запрос SQL в Oracle 11g.

SELECT p.matchcode      pmatchcode,
       p1.matchcode     p1matchcode,
       p.digits         digit,
       p1.effectivedate peff,
       p1.expirydate    pexp,
       p.expirydate     p1exp,
       p.tariff_id      tariff_id
  FROM tt_matchcodes_view p1
  JOIN tt_matchcodes_view p
    on p.tariff_id = p1.tariff_id
   AND p.type_id = p1.type_id
   AND p1.Digits = p.Digits
   AND p.matchcode <> p1.matchcode
   AND p1.EffectiveDate < p.expirydate
   AND (p1.expirydate IS NULL OR p1.expirydate > p.expirydate)
   AND substr(p.matchcode, 0, length(p1.matchcode)) = p1.matchcode;

В таблице tt_matchcodes_view содержится 71392 записей.Я создал два индекса на этой таблице в полях matchcode and digits.Выполнение занимает более 10 минут.Есть ли в любом случае сократить время выполнения.

Пример таблицы данных:

MATCHCODE   DIGITS  DEST_ID MATCH   EFFECTIVEDATE   EXPIRYDATE  INHERITED   TARIFF_ID   TYPE_ID
1787    1787    73999   1   01/03/2012      0   22  1
1787201 1787    73999   0   01/03/2012      -1  22  1
1787202 1787    73999   0   01/03/2012      -1  22  1
1787203 1787    73999   0   01/03/2012      -1  22  1
1787204 1787    73999   0   01/03/2012      -1  22  1
1787205 1787    73999   0   01/03/2012      -1  22  1
1787206 1787    73999   0   01/03/2012      -1  22  1
1787207 1787    73999   0   01/03/2012      -1  22  1
1787208 1787    73999   0   01/03/2012      -1  22  1
1787212 1787    73999   0   01/03/2012      -1  22  1

Выполнение ПЛАН:

OPERATION   OPTIONS OBJECT_NAME OBJECT_INSTANCE OPTIMIZER   ID  PARENT_ID   DEPTH   POSITION    COST    CARDINALITY BYTES   CPU_COST    IO_COST
SELECT STATEMENT                ALL_ROWS    0       0   703 703 3   501 83322403    698
HASH JOIN                   1   0   1   1   703 3   501 83322403    698
TABLE ACCESS    FULL    TT_MATCHCODES_VIEW  2       2   1   2   1   95  65498   5174342 22711001    94
TABLE ACCESS    FULL    TT_MATCHCODES_VIEW  1       3   1   2   2   95  65498   5763824 22711001    94

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 27 марта 2012

Ваша таблица содержит более 70000 строк.Вы выбираете все его записи дважды и сравниваете строки на основе неравенства.Таким образом, в основном вы сравниваете каждую строку с каждой другой строкой в ​​таблице.(Не все из них, потому что не те, где TARIFF_ID, TYPE_ID или DIGITS не совпадают, но их не так много). Это ~ 490 000 000 сравнений.Десять минут выполнения не кажутся слишком плохими в данных обстоятельствах.

План объяснения показывает, что Oracle выбрал лучший план, который он может.Все, что вы можете сделать, чтобы улучшить это, это дать Oracle более полезный индекс.Составной индекс, который использует все столбцы в предложении where, может помочь.Примерно так:

create index super_match_idx on tt_matchcodes_view
    (tariff_id, .type_id, digits, matchcode, expirydate, effectivedate )    

Это может дать вам два ПОЛНЫХ БЫСТРОГО СКАНИРОВАНИЯ в индексе, что должно быть быстрее, чем две операции ПОЛНОГО СКАНИРОВАНИЯ.

Кстати, вы сортируете данные, когдаВы заполняете временную таблицу?Использование ORDER BY, который совпадает с индексом, улучшит коэффициент кластеризации.Таким образом, вы можете получить более быстрый поиск, поскольку все совпадающие строки с большей вероятностью будут находиться в смежных блоках.

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

Ох, и substr(p.matchcode, 0, length(p1.matchcode)) - это мертвая распродажа.Умные клавиши - это отстой!В любом случае, есть ли когда-нибудь случай, когда этот вызов SUBSTR () возвращает значение, которое не соответствует DIGITS?(Опять же, ваши примеры данных неоднозначны.) Если DIGITS достоверно идентифицирует выходные данные SUBTSR (), я предлагаю вам отказаться от этой последней строки.

1 голос
/ 27 марта 2012

Поскольку это глобальная временная таблица, вы должны заполнить ее, а затем выполнить запрос в том же сеансе или даже транзакции.Это заставляет меня задуматься, есть ли у Oracle статистика по таблице, собранной, когда она была пустой, которая не отражает ее фактическое содержимое.Вы можете попробовать собрать статистику непосредственно перед выполнением запроса.Если это работает, и содержимое таблицы не должно сильно отличаться от одного прогона к следующему, вы можете просто закрепить эти статистические данные, чтобы они не были заменены.

Однако, на основеИнформация, которую вы предоставили до сих пор, я не уверен, что есть лучший план, который мог бы предложить Oracle.Индекс только по matchcode вряд ли будет пригоден для этого запроса, учитывая условия в нем в предикате.Можно использовать индекс на digits, но поскольку вы присоединяете таблицу к себе, это, вероятно, будет менее эффективным, чем простое выполнение двух полных сканирований, поскольку всегда будет совпадение на digits (кроме случаев, когда он равен NULL,если когда-либо).

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

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