В последнем отчете об ошибке говорится, что вызываемый метод вызывает сбой службы, заставляющей ее перезапускаться. После устранения неполадок было обнаружено, что причиной является неприятный вызов Oracle SQL с переданными тысячами строк. Существует набор строк, передаваемых методу из внешней службы, которая часто составляет более 10 000 записей. Исходный код использовал предложение where в переданной коллекции, используя ключевое слово LIKE, которое, на мой взгляд, действительно очень плохое.Обработка больших объемов данных для включения в операторе выбора оракула
public IList<ContainerState> GetContainerStates(IList<string> containerNumbers)
{
string sql =
String.Format(@"Select CTNR_NO, CNTR_STATE FROM CONTAINERS WHERE CTRN_SEQ = 0 AND ({0})",
string.Join("OR", containerNumbers
.Select(item => string.Concat(" cntr_no LIKE '", item.SliceLeft(10), "%' ")))
);
return DataBase.SelectQuery(sql, MapRecordToContainerState, new { }).ToList();
}
Уточнение в методах, используемых дома, которые могут ввести в заблуждение:
DataBase.SelectQuery внутренний метод библиотеки с использованием обобщенных типов, который получает выдержавших строку SQL, функцию для отображения записей в. NET и передаваемые параметры и возвращает IEnumerable объектов типа, перенастроенных функцией Mapping.
SliceLeft - это метод расширения из другой внутренней вспомогательной библиотеки, которая возвращает только первую часть строки до количества символов, заданных параметром.
Причина, по которой LIKE заявление, видимо, используется, в том, что строки передается и строки в базе данных только гарантированно соответствовать первые 10 символов. Пример («XXXX000000-1» в передаваемых строках должен соответствовать записи базы данных, такой как «XXXX000000-8»).
Я считал, что положение в использовании SUBSTR будет более ЭФФЕКТИВНАЯ, чем использование нескольких положений LIKE и заменить код:
public IList<ContainerRecord> GetContainerStates(IList<string> containerNumbers)
{
string sql =
String.Format(@"Select CTNR_NO, CNTR_STATE FROM CONTAINERS WHERE CTRN_SEQ = 0 AND ({0})",
string.Format("SUBSTR(CNTR_NO, 1, 10) IN ({0}) ",
string.Join(",", containerNumbers.Select(item => string.Format("\'{0}\'", item.SliceLeft(10))))
)
);
return DataBase.SelectQuery(sql, MapRecordToContainerState, new { }).ToList();
}
Это помогло немного, и было меньше проблем в моих тестах, но когда есть огромное количество пропущенных записей, все еще есть исключение, и появляются дампы ядра, поскольку SQL длиннее, чем сервер может анализировать в течение этих времен. Администратор баз данных предлагает сохранить все строки, переданные во временную таблицу, а затем присоединиться к этой временной таблице.
Учитывая, что совет, я изменил функцию:
public IList<ContainerRecord> GetContainerStates(IList<string> containerNumbers)
{
string sql =
@"
CREATE TABLE T1(cntr_num VARCHAR2(10));
DECLARE GLOBAL TEMPORARY TABLE SESSION.T1 NOT LOGGED;
INSERT INTO SESSION.T1 VALUES (:containerNumbers);
SELECT
DISTINCT cntr_no,
'_IT' cntr_state
FROM
tb_master
WHERE
cntr_seq = 0
AND cntr_state IN ({0})
AND adjustment <> :adjustment
AND SUBSTR(CTNR_NO, 1, 10) IN (SELECT CNTR_NUM FROM SESSION.T1);
";
var parameters = new
{
@containerNumbers = containerNumbers.Select(item => item.SliceLeft(10)).ToList()
};
return DataBase.SelectQuery(sql, MapRecordToContainerState, parameters).ToList();
}
Сейчас я получаю "ORA-00900: недопустимое заявление SQL". Это действительно расстраивает, как я могу правильно написать заявление SQL, которое поместит этот список строк во временную таблицу и затем будет использовать его в инструкции SELECT, чтобы вернуть список, который мне нужен?
несколько быстрых заметок: если вы хотите использовать глобальную временную таблицу, вы создаете его один раз (за пределами какой-либо процедуры или метода, который использует его), а затем использовать он (вставить/выбрать/удалить) внутри процедуры. Кроме того, его сеанс специфичен, что может повлиять на его использование в зависимости от вашей настройки. Например, см. [Здесь] (http://stackoverflow.com/questions/9310860/how-to-create-and-use-temporary-table-in-oracle-stored-procedure/9310979#9310979) – tbone