Проблемы с производительностью хранимых процедур ODP.Net в больших наборах данных
-
18-09-2019 - |
Вопрос
У нас возникли серьезные проблемы с производительностью запросов SELECT к одной из наших баз данных.Пожалуйста, ознакомьтесь с простой процедурой и соответствующим кодом ниже.
В коде метод ExecuteReader() выполняется примерно за 10 секунд по запросу, возвращающему 30 тысяч записей.Итерация Reader занимает 2 минуты (даже если я не перекачиваю данные в какой-либо другой объект).2 минуты для набора данных из 30 тысяч строк для нас неприемлемы, поскольку мы ожидаем, что наборы данных исчисляются миллионами.
Есть ли здесь что-то, что запомнилось кому-нибудь из вас?Надеемся, что ваш опыт работы с ODP.NET и PL/SQL может вам помочь.
create or replace PROCEDURE TRACKING_FETCH (
p_tracking_id IN NUMBER,
p_parent_id IN NUMBER,
p_media_id IN NUMBER,
p_custodian_id IN NUMBER,
p_return_cursor OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_return_cursor FOR
SELECT
*
FROM
tracking
WHERE
(tracking_id = p_tracking_id OR p_tracking_id = 0)
AND (parent_id = p_parent_id OR p_parent_id = 0)
AND (media_id = p_media_id OR p_media_id = 0)
AND (custodian_id = p_custodian_id OR p_custodian_id = 0);
END TRACKING_FETCH;
--
using (DataFactory command
= new DataFactory(dbConnection,
DatabaseType.Oracle,
CommandType.StoredProcedure,
"TRACKING_FETCH"))
{
command.AddInParameter("p_tracking_id", DbType.Int32, trackingid);
command.AddInParameter("p_parent_id", DbType.Int32, parentid);
command.AddInParameter("p_media_id", DbType.Int32, mediaid);
command.AddInParameter("p_custodian_id", DbType.Int32, custodianid);
using (var dr = command.ExecuteReader())
{
while (dr.Read())
{
//Do Things...
}
}
}
Любое руководство будет высоко оценено.
Решение
Стоит изучить интерфейс ожидания Oracle.Я подозреваю, что задержка в сети вас убивает.Процедура возвращает указатель на набор результатов.Я предполагаю, что в какой-то момент вашего цикла вы извлекаете строки (даже если они сбрасываются).
Проверка v$sql покажет вам, сколько выборок выполняется и сколько строк обрабатывается.Разделите одно на другое, и вы увидите, сколько строк приходится на выборку.Если вы выполняете 1 строку/выборку или даже 10–20, это тысячи сетевых ожиданий.В идеале вам нужны тысячи строк за выборку, если вы собираетесь извлекать миллионы записей, хотя это может стоить вам памяти.
В зависимости от того, что вы делаете с этими миллионами строк, возможно, стоит переосмыслить архитектуру.Например, если они сбрасываются в файл, возможно, сгенерируйте файл на сервере БД, заархивируйте его, переместите файл по сети, а затем разархивируйте его.
Другие советы
Вы пробовали запустить EXPLAIN PLAN
в хранимой процедуре?Я не вижу каких-либо непосредственных проблем ни с вашим кодом, ни с вашей хранимой процедурой, но полное сканирование таблицы серьезно сократит время выполнения вашего запроса.План объяснения сообщит вам, есть ли сканирование таблиц, а затем вы сможете настроить свой запрос, чтобы ускорить его.
Это не проблема вашей программы odp.net.Причина в SELECT.Если таблица содержит много записей, возможно, оптимизатор решит выполнить полное сканирование таблицы, в зависимости от ваших параметров.Проверить с объяснить план как работает заявление.Если вы не видите ничего полезного.Попробуй след оператор просмотра физического чтения.