Команда Oracle зависает при использовании представления для подзапроса "WHERE x IN ..." - PullRequest
0 голосов
/ 24 апреля 2010

Я работаю над веб-сервисом, который извлекает данные из источника данных Oracle в виде фрагментов и передает их обратно в инструмент индексирования / поиска в формате XML. Я парень из C # / .NET, и немного нечеткий в части Oracle.

Наша команда Oracle дала нам запустить следующий скрипт, и он хорошо работает:

SELECT ROWID, [columns]
FROM [table]
WHERE ROWID IN (
    SELECT ROWID
    FROM (
        SELECT ROWID
        FROM [table]
        WHERE ROWID > '[previous_batch_last_rowid]'
        ORDER BY ROWID
    )
    WHERE ROWNUM <= 10000
)
ORDER BY ROWID

10000 строк - это произвольный, но разумный размер фрагмента, а ROWID достаточно уникален для наших целей, чтобы использовать его в качестве UID, поскольку каждый прогон индексирования затрагивает только одну таблицу за раз. Значения в квадратных скобках заполняются программно веб-службой.

Теперь мы собираемся начать добавлять представления к индексации, каждая из которых объединит несколько отдельных таблиц. Поскольку ROWID больше не будет функционировать как уникальный идентификатор, они добавили столбец к представлениям (VIEW_UNIQUE_ID), который объединяет ROWID из таблиц компонентов, чтобы создать UID для каждого объединения.

Но этот скрипт не работает, даже если он имеет ту же форму, что и предыдущий:

SELECT VIEW_UNIQUE_ID, [columns]
FROM [view]
WHERE VIEW_UNIQUE_ID IN (
    SELECT VIEW_UNIQUE_ID
    FROM (
        SELECT VIEW_UNIQUE_ID
        FROM [view]
        WHERE VIEW_UNIQUE_ID > '[previous_batch_last_view_unique_id]'
        ORDER BY VIEW_UNIQUE_ID
    )
    WHERE ROWNUM <= 10000
)
ORDER BY VIEW_UNIQUE_ID

Он зависает бесконечно без ответа от сервера Oracle. Я ждал более 20 минут, и диалоговое окно SQLTools, указывающее, что запущенный запрос остается тем же, без прогресса или обновлений.

Я протестировал каждый подзапрос независимо, и каждый работает нормально и занимает очень короткое время (<= 1 секунда), поэтому само представление является звуковым. Но как только два внутренних запроса SELECT добавляются с "WHERE VIEW_UNIQUE_ID IN ...", он зависает. </p>

Почему этот запрос не работает для представлений? Чем они здесь взаимозаменяемы?

Обновлено : архитектура решения предусматривает отсутствие состояния, поэтому я не должен пытаться заставить веб-службу сохранять какую-либо информацию о состоянии индекса между запросами от потребителей.

Ответы [ 2 ]

3 голосов
/ 24 апреля 2010

они добавили столбец к представлениям (VIEW_UNIQUE_ID), который объединяет ROWID из таблиц компонентов в построить UID для каждого объединения.

Боже, это самая непристойная идея, которую я видел за долгое время. Допустим, представление является простым, как

SELECT C.CUST_ID, C.CUST_NAME, O.ORDER_ID, C.ROWID||':'||O.ROWID VIEW_UNIQUE_ID
FROM CUSTOMER C JOIN ORDER O ON C.CUST_ID = O.CUST_ID

Каждый раз, когда вы хотите сделать

SELECT VIEW_UNIQUE_ID
FROM [view]
WHERE VIEW_UNIQUE_ID > '[previous_batch_last_view_unique_id]'
ORDER BY VIEW_UNIQUE_ID

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

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

1 голос
/ 27 апреля 2010

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

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

INSERT INTO pending_table
SELECT 'N' state_flag, v.* FROM view v;

<start looping here>

UPDATE pending_table
SET state_flag = 'P'
WHERE ROWNUM < 10000;

COMMIT;

SELECT * FROM pending_table
WHERE state_flag = 'P';

<client processing>

DELETE FROM pending_table
WHERE state_flag = 'P';

<go back to start of loop, and keep going until pending_table is empty>
...