2015-04-09 1 views
0

У меня есть программа, которая должна запускать запросы на несколько очень больших таблиц Oracle (самая большая с десятками миллионов строк). Вывод этих запросов подается в другой процесс, который (в качестве побочного эффекта) может записывать ход запроса (т. Е. Извлекается последняя строка).Каков наилучший способ обеспечения согласованного заказа в запросе Oracle?

Было бы неплохо, если в какой-то причине задача остановилась на полпути по какой-либо причине, ее можно было бы перезапустить. Чтобы это произошло, запрос должен возвращать строки в последовательном порядке, поэтому его нужно сортировать. Очевидно, что нужно сортировать первичный ключ; однако, вероятно, это будет штраф за это с точки зрения производительности (доступ к индексу) по сравнению с неупорядоченным решением. Учитывая, что перезапуск может никогда не произойти, это нежелательно.

Есть ли какой-то трюк, чтобы обеспечить последовательный заказ по-другому? Любые другие предложения по поддержанию производительности в этом случае?

EDIT: Я оглядывался и видел «заказ по rowid». Это полезно или даже возможно?

EDIT2: Я добавляю некоторые тесты:

  • При отсутствии приказа: 17 секунд.
  • С заказом от PK: 46 секунд.
  • С заказом rowid: 43 секунды.

Таким образом, любой заказ имеет дикий эффект на производительность, а использование rowid мало чем отличается. Принятый ответ - нет простого способа сделать это.

+1

Почему, по вашему мнению, будет использоваться доступ к индексу? Если большая часть данных будет извлечена, индекс будет бессмысленным. Ваша единственная гарантия для строк, отображаемых в последовательном порядке (например, по возрастанию первичного ключа), заключается в использовании предложения ORDER BY. Однако вам также нужно учитывать такие вещи, как, если кто-то вставляет новые данные, которые появляются на середине в упорядоченном наборе результатов, между запуском и перезапуском запроса? Это может отбросить вещи. Однако сортировка вашего набора результатов, скорее всего, повлияет на производительность. – Boneist

+0

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

+0

Индекс не обязательно будет использоваться для сортировки. И это не основные изменения таблиц, о которых я говорил, но скажем, что у вас есть строки с идентификаторами pk 1, 3, 5 и 7, поэтому вы заказываете свои результаты в столбце id. Предположим, что вы остановились после третьей строки, а затем кто-то вставляет строку с id = 4. Когда вы перезагружаете свой запрос, строка с id = 5 уже не является третьей в результирующем наборе, это четвертый, поэтому ваши результаты не являются согласованный по обеим прогонам. – Boneist

ответ

3

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

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

+0

Голосование за то, что в основном говорят «вы не можете», который всегда является отважным ответом! Я соглашусь, если не найду альтернативы. – rghome

+0

О, конечно, всегда есть альтернатива. Однако это определенно компромисс.Я был в ситуациях, когда было абсолютно необходимо, чтобы работа была «восстановимой», потому что она должна была работать каждые 24 часа и потребовалась 18 для завершения. Имейте в виду, если бы это было более простое и не восстанавливаемое, оно могло бы быть взято только в 12 раз. В 95% случаев я столкнулся с лучшей защитой, что было хорошим преступлением, а это означало небольшой, быстрый, некоммерческий код. –

1

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

  1. Минимизировать ресурсы, затраченные на сортировке;
  2. Запрос уже отсортированных данных.

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

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

Подумайте о таблице с суррогатным основным ключом, который содержит данные с 10-летней историей транзакций. Если вам нужны данные только за предыдущий год, и вы принудительно упорядочиваете первичный ключ, тогда Oracle необходимо обрабатывать записи за каждые 10 лет один за другим, чтобы найти все записи, принадлежащие одному году.
Но если вам нужны данные за 9 лет из этой таблицы, то полное сканирование таблицы может быть быстрее, чем выбор на основе индекса.
Таким образом, избирательность вашего запроса - это ключ к выбору полного сканирования таблицы и сортировки результатов.

Для хранения результатов и перезапуска запроса хорошим решением является использование Oracle Streams Advanced Queuing для подачи другого процесса.
Все необработанные сообщения в очереди перенаправляются в очередь исключения, где она может обрабатываться отдельно.
Поскольку вы не указываете точный порядок для выбранных сообщений, я полагаю, что вам нужно только заказать необработанную часть записей. Если это правда, то с AQ вам вообще не нужно упорядочивать и даже, возможно, обрабатывать записи параллельно.

Итак, с моей точки зрения Buffered Queue - это то, что вам действительно нужно.

+0

Просто для того, чтобы прояснить момент, начинающийся «Подумай ...»: на самом деле мне, вероятно, понадобится более 95% таблицы, поэтому для неупорядоченного выбора FTS это то, что он будет делать, и, насколько я вижу, у него нет причин смотреть на первичный индекс. Но если я добавлю заказ на ПК, он должен посмотреть на этот индекс. Таким образом, на самом деле более ограничительный выбор на ПК будет относительно условно, поскольку он должен будет получить доступ к индексу в любом случае для ГДЕ, поэтому ничего не потеряно, используя его для сортировки. Но в моем случае индекс обычно не требуется, поэтому сортировка является чистой накладной. – rghome

+0

Обратите внимание, что я упоминаю [индексированные таблицы] (https://docs.oracle.com/cd/B28359_01/server.111/b28310/tables012.htm#ADMIN11703), которые не добавляли служебные данные, если отсортированы результаты запроса только по первичному ключу. Но реорганизация большого стола - это проблема сама по себе, поэтому она может быть неприменима в вашем случае. – ThinkJet

+0

Да - не доступно в моем случае. Спасибо, в любом случае. – rghome

0

Вы можете пропустить заказ и просто обновить записи, обработанные с помощью чего-то вроде SET is_processed = 'Y' или SET date_processed = sysdate. Полная перезапуск и отсутствие заказа.

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

+0

Я думаю, что обновление будет медленнее, чем сортировка по первичному ключу. Плюс я должен был бы сделать условие на флажках. Оптимизатору по-прежнему потребуется полное сканирование таблицы, поскольку в этих столбцах не будет индекса, и если бы он был, его нужно было бы обновить, что бы замедлить его, и у него, вероятно, не было бы достаточно высокой мощности, чтобы иметь эффект в любом случае , – rghome

+0

Отредактированный ответ, чтобы решить эту проблему. – jva