У нас есть очень сложный пакет Oracle (более 4100 строк кода), который вызывает у нас проблемы. Мне было поручено отследить проблему. Проблема в том, что когда мы вызываем процедуру execute_filter
, мы ожидаем получить 6 таблиц. Тем не менее, примерно 10-15 раз в день наш код падает, потому что индекс таблицы 1 находится вне диапазона. Когда это повторяется, кажется, что оно повторяется несколько раз, а через минуту снова отлично работает. Я все еще не смог воспроизвести это в отладчике, чтобы точно узнать, что это за набор данных, но у меня есть теория, что набор данных - это просто одна пустая таблица.
Копаться в пакете Oracle практически невозможно, так как это все один большой рабочий запрос без форматирования, без отступов, а также страниц и страниц кода, который строит другие запросы путем объединения строк, а что нет. Тем не менее, у меня есть теория о том, что происходит.
Метод execute_filter
вызывает один или несколько десятков других методов, например filter_by_areas_name
. Каждый из этих методов запрашивает некоторые данные и вставляет эти данные в таблицу с именем tpm_temp_filter_project
. Примером этого является:
FOR I IN 1..areaState.COUNT LOOP
INSERT INTO tpm_temp_filter_project
(
projectid,
versionid
)
SELECT .. --Grabs the data it needs from other tables
В конце каждого из этих вызовов фильтра мы вызываем процедуру с именем populate_result_table
, которая копирует данные из tpm_temp_filter_project
в другую таблицу и затем выполняет:
EXECUTE IMMEDIATE 'truncate table tpm_temp_filter_project';
Итак, моя теория состоит в том, что если два человека выполняют этот запрос одновременно, строки из этих таблиц "держателей" преждевременно усекаются, в то время как другой запрос все еще нуждается в них.
Как лучше всего предотвратить подобные вещи? Одна идея, которая у меня была, заключалась в следующем:
LOCK TABLE tpm_temp_filter_project IN EXCLUSIVE MODE;
В самом начале execute_filter
и COMMIT;
в качестве самой последней строки. Теоретически, это должно позволить только одному человеку выполнять команду одновременно, и ожидающие запросы будут «блокироваться» до тех пор, пока не будет выполнен первый фильтр. Я еще не пробовал, но у меня есть несколько вопросов.
- Это хорошая теория относительно того, что происходит?
- Это хорошее исправление или есть лучшее решение этой проблемы?
Я ценю любое понимание этой проблемы.
UPDATE:
Вот схема для временной таблицы:
CREATE GLOBAL TEMPORARY TABLE TPMDBO.TPM_TEMP_FILTER_PROJECT (
PROJECTID NUMBER NULL,
VERSIONID NUMBER NULL
)
ON COMMIT DELETE ROWS
ДРУГОЕ ОБНОВЛЕНИЕ:
Это, похоже, не конфликт между двумя сессиями. Если я изменюсь:
EXECUTE IMMEDIATE 'truncate table tpm_temp_filter_project';
до:
DELETE tpm_temp_filter_project;
тогда ошибка по-прежнему возникает. Даже если я закомментирую эту строку полностью, ошибка все равно в конечном итоге произойдет. В этом теле пакета больше нет ничего, что удаляет, усекает или изменяет любые другие данные.
Второе доказательство - я, наконец, повторил ошибку в отладчике Visual Studio. DataSet в .NET полностью пуст. Есть одна таблица с именем table , которая имеет нулевые столбцы. Если бы это была проблема с одним сеансом, удаляющим данные в этих временных таблицах, то я ожидал бы, что допустимая схема с нулевыми строками или, возможно, строками из неправильного сеанса.