powered by simpleCommunicator - 2.0.29     © 2024 Programmizd 02
Map
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Чрезмерное использование RAM при запросах к базе данных
17 сообщений из 17, страница 1 из 1
Чрезмерное использование RAM при запросах к базе данных
    #40115124
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте, есть метод, который грубо говоря делает следующее:
принимает в качестве параметра список ID, по каждому из которых надо сходить в базу данных и стянуть еще дополнительную информацию.
То есть нужно сделать около 300-400 небольших запросов последовательно.
В качестве клиента подключения для базы данных используется Oracle.ManagedDataAccess.Core 3.21.4
В качестве текущей версии фреймворка: NET5.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
 public async Task<List<flattenedDto>> EnrichDataByOracleAsync(IEnumerable<FromExcelDto> xlItems)
        {
            using var oracleConnection = new OracleConnection(_oracleConnectionString);
            await oracleConnection.OpenAsync();
            var resultList = new List<flattenedDto>();
      
            foreach (var xlItem in xlItems)
            {
                var result = await oracleConnection.QueryAsync<DapperDto>(
                     "select ...",
                     new { param1 = xlItem.ID,param2= xlItem.param2 });

                if (result != null)
                {
                    foreach (var bk in result)
                        resultList.Add(new flattenedDto(
                            bk.quantity,
                            xlItem.ID
                            ));
                }
                else
                {
                    throw new Exception("Данные не найдены в базе данных");
                }
            }
            return resultList;
        }


Проблема в том, что на выполнение одного прогона метода уходит дополнительно +80 мб RAM при дебажной конфигурации- вряд ли при релизной она как-нибудь починится. Причем память растет с каждым вызовом, может до 1.3 GB вырасти и GarbageCollector не спешит её чистить. При анализе снимков обнаружено, что самым занимаемым компонентом в памяти является OracleInternal.Common.ZoneValue. Соответственно вопрос- как можно ограничить в аппетитах этот OracleInternal.Common.ZoneValue? Спасибо
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115137
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Перегнать IEnumerable<FromExcelDto> (эти самые xlItems) в xml, передать его на сервер, там распарсить (300-400 узлов - это, в общем-то, ерунда), и получить всё требуемое одним запросом не пробовали?
vb_sub
+80 мб RAM при дебажной конфигурации- вряд ли при релизной она как-нибудь починится.

Почему вряд ли? Дебаг в памяти держит очень много всякого, чего не держит релиз. Я бы проверил и убедился.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115141
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны,
к сожалению доступ к администрированию БД отсутствует, поэтому не могу создавать свои обработки.
Сон Веры Павловныполучить всё требуемое одним запросом не пробовали
Рассматривал такие варианты, но теоретически они мне показались один хуже другого и точно хуже выше описанного варианта.
1) Создать один мега запрос вида
Код: plsql
1.
select entinity.info from table where 	entinity.id in (1,2,3,4,5,6 ...400)

,
где (1,2,3,4,5,6 ...400) - составленно из списка IEnumerable<FromExcelDto>
2)Создать один запрос, который возвращает multySet результатов
Код: plsql
1.
2.
3.
4.
5.
6.
        select entinity.info from table where 	entinity.id=1;
	select entinity.info from table where 	entinity.id=2;
	select entinity.info from table where 	entinity.id=3;
	select entinity.info from table where 	entinity.id=4;
	...
	select entinity.info from table where 	entinity.id=400;


Возможно эти два варианта даже полностью решат проблему с памятью на клиентском приложении, но от них уже станет плохо базе данных- таким образом я просто передислоцирую проблему в другое место, но не устраню её.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115144
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
и точно хуже выше описанного варианта

Эм. На основании чего был сделан такой вывод? Планы запросов смотрели? Трейсы снимали?
Ещё, как вариант, в транзакции залить список в GTT, используя array binding, и выполнять запрос с джойном к GTT.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115145
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны,
попробую протестировать на практике.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115356
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vb_sub,

А через временную таблицу?
Сначала туда загнать (INSERT tmp (ID) VALUES (1)), а потом временную таблицу использовать в запросе.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115406
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны
Ещё, как вариант, в транзакции залить список в GTT, используя array binding, и выполнять запрос с джойном к GTT.

SergiiW
Сначала туда загнать (INSERT tmp (ID) VALUES (1)), а потом временную таблицу использовать в запросе.

GTT (global temporary table) - это и есть оракловая временная таблица, а array binding - некий аналог MSSQL'ного bulk insert.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115792
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем поэкспериментировал я с разными вариантами реализации и пришел к выводу, что оверхед возникает не в момент многократного вызова комманд.
Я перевел текст запроса параметрами в строковую константу и однократно отправил её для получения данных - в итоге получил такое же RAM потребление, как и в первом сообщении.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40115969
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А если попробовать по старинке через DataReader?
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116023
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
А если попробовать по старинке через DataReader?

не умеет
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116031
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
В общем поэкспериментировал я с разными вариантами реализации и пришел к выводу, что оверхед возникает не в момент многократного вызова комманд.

А LOB'ы этим запросом вытаскиваются? В гугле дофига и больше вопросов и сообщений по запросу "oracle manageddataaccess memory leak", и практически все в той или иной степени связаны с работой с LOB.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116046
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRos
fkthat
А если попробовать по старинке через DataReader?

не умеет

умеет
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116048
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat,
тоже самое
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116050
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны
vb_sub
В общем поэкспериментировал я с разными вариантами реализации и пришел к выводу, что оверхед возникает не в момент многократного вызова комманд.

А LOB'ы этим запросом вытаскиваются? В гугле дофига и больше вопросов и сообщений по запросу "oracle manageddataaccess memory leak", и практически все в той или иной степени связаны с работой с LOB.

Думаю вряд ли здесь имеет смысл работать с LOB- ведь по факту за 300 запросов в итоге приходит около 1000 строк с 5 текстовыми полями длиной до 255- то есть никаких супертяжелых объемов данных в ответ не приходит.
Сон Веры ПавловныВ гугле дофига и больше вопросов и сообщений по запросу "oracle manageddataaccess memory leak"
99% топиков из-за неверно закрытого using.
Единственно релевантный топик по моей проблеме
ссыль - но там чел вообще отчаялся и полез GarbageCollector'y объяснять как ему лучше работать.
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116383
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
Единственно релевантный топик по моей проблеме
ссыль - но там чел вообще отчаялся и полез GarbageCollector'y объяснять как ему лучше работать.

Интересно.
Как инстанциируется эта OracleInternal.Common.ZoneValue (структура, хранит в себе массив структур) (весь код ниже - от декомпиляции ILSpy):
1. Метод OracleInternal.Common.OracleTimeZone.GetInstance:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
private static OracleTimeZone tzCacheObj;

[SecurityPermission(SecurityAction.Assert, SerializationFormatter = true)]
internal static OracleTimeZone GetInstance()
{
	try
	{
		if (tzCacheObj == null)
			tzCacheObj = new TimeZoneFileReader().ReadObj();
	}
	catch (Exception ex)
	{
		throw ex;
	}
	return tzCacheObj;
}


2. Метод OracleInternal.Common.TimeZoneFileReader.ReadObj:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
internal OracleTimeZone ReadObj()
{
	int latestTZVersion = 0;
	string name = "";
	Assembly executingAssembly = Assembly.GetExecutingAssembly();
	string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
	foreach (string text in manifestResourceNames)
	{
		if (text.StartsWith("OracleInternal.I18N.TimeZone", StringComparison.InvariantCultureIgnoreCase)
				&& text.EndsWith(".dst", StringComparison.InvariantCultureIgnoreCase))
		{
			latestTZVersion = Convert.ToInt32(text.Split('_', '.')[3]);
			name = text;
			break;
		}
	}
	using (GZipStream gZipStream = new GZipStream(executingAssembly.GetManifestResourceStream(name), CompressionMode.Decompress))
		using (MemoryStream memoryStream = new MemoryStream())
		{
			gZipStream.CopyTo(memoryStream);
			memoryStream.Position = 0L;
			BinaryReader binaryReader = new BinaryReader(memoryStream);
			LTZHead lTZHead = new LTZHead();
			int errcode = -1;
			lTZHead = PopulateHead(binaryReader, out errcode);
			if (errcode != 0)
				throw new Exception("Errorcode not present, Error in populating the head");
			LdiDateTime[] dttab = ReadTransitionsOfAllZones(lTZHead, binaryReader);
			LTZtag[] tagtab = PopulateTagArray(lTZHead, binaryReader);
			short[] tagmap = PopulateTagMapArray(lTZHead, binaryReader);
			byte[] dstflag = PopulateDSTFlagArray(lTZHead, binaryReader);
			Dictionary<int, string> zoneIdMap = PopulateZoneIdMapHashtable(lTZHead, binaryReader);
			Hashtable zoneIdtoOffsetMap = PopulateZoneOffsetMapHashtable(lTZHead, dttab, tagmap, tagtab, dstflag);
			OracleTimeZone oracleTimeZone = new OracleTimeZone();
			oracleTimeZone.SetZoneIdMap(zoneIdMap);
			oracleTimeZone.SetZoneIdtoOffsetMap(zoneIdtoOffsetMap);
			oracleTimeZone.SetLatestTZVersion(latestTZVersion);
			binaryReader.Close();
			return oracleTimeZone;
		}
}


3. Метод OracleInternal.Common.TimeZoneFileReader.PopulateZoneOffsetMapHashtable:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
internal Hashtable PopulateZoneOffsetMapHashtable(LTZHead head, LdiDateTime[] dttab, short[] tagmap, LTZtag[] tagtab, byte[] dstflag)
{
	Hashtable hashtable = new Hashtable();
	for (int i = 0; i < 8192; i++)
	{
		ZoneValue zoneValue = default(ZoneValue);
		LTZMeta lTZMeta = head.meta_ltzhead[i];
		uint ntrans_ltzmeta;
		if ((ntrans_ltzmeta = (uint)lTZMeta.ntrans_ltzmeta) == 0)
			continue;
		zoneValue.m_transitions = new Transitions[ntrans_ltzmeta];
		int num = 0;
		for (int j = 0; j < ntrans_ltzmeta; j++)
		{
			int num2 = lTZMeta.trans_ltzmeta + j;
			LdiDateTime ldiDateTime = dttab[num2];
			short num3 = tagmap[num2];
			LTZtag lTZtag = tagtab[num3];
			zoneValue.m_transitions[j] = default(Transitions);
			zoneValue.m_transitions[j].m_dateTimeInUtc = new DateTime(
				ldiDateTime.year_LdiDateTime,
				ldiDateTime.month_LdiDateTime,
				ldiDateTime.day_LdiDateTime,
				ldiDateTime.hour_LdiDateTime,
				ldiDateTime.minute_LdiDateTime,
				ldiDateTime.second_LdiDateTime
			);
			zoneValue.m_transitions[j].m_hourOffset = GetTimeSpan(lTZtag.gmtoff_ltztag);
			zoneValue.m_transitions[j].m_dst = dstflag[num2];
			zoneValue.m_transitions[j].m_dateTimeInLocal = zoneValue.m_transitions[j].m_dateTimeInUtc.Add(zoneValue.m_transitions[j].m_hourOffset);
			int num4 = lTZtag.gmtoff_ltztag - num;
			if (num4 < 0)
				num4 = -num4;
			zoneValue.m_transitions[j].m_dstDuration = GetTimeSpan(num4);
			if (zoneValue.m_transitions[j].m_dst != 0)
				zoneValue.m_transitions[j].m_dateTimeInLocal = zoneValue.m_transitions[j].m_dateTimeInLocal.Add(GetTimeSpan(-num4));
			num = lTZtag.gmtoff_ltztag;
		}
		hashtable.Add(i, zoneValue);
	}
	return hashtable;
}


- и всё, больше никак и нигде. Получается, что OracleInternal.Common.OracleTimeZone.GetInstance на каждый запрос вызывает OracleInternal.Common.TimeZoneFileReader.ReadObj - т.е. где-то как-то статическое поле класса сбрасывается в null. И что интересно - у меня на попечении есть несколько заданий по расписанию для оракла, которые выполняются несколько раз в день, и сами выполняют достаточно много запросов, но никаких утечек памяти в них не обнаруживалось. Эти задания написаны на обычном .Net framework, а в версии ODP.Net код фактически эквивалентен вышеприведенному. То ли в Core как-то по-другому устроен жизненный цикл статик-полей, то ли ещё что. Но, видимо, принудительная сборка мусора здесь действительно единственный выход (до тех пор, пока ораклисты сами не поправят этот баг).
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116397
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныПочему вряд ли? Дебаг в памяти держит очень много всякого, чего не держит релиз. Я бы проверил и убедился.
Релиз проблему не странил.
Где можно создать issue с этой проблемой? Разработчик Nuget для Oracle.ManagedDataAccess.Core 3.21.4, или саппорт Oracle?
...
Рейтинг: 0 / 0
Чрезмерное использование RAM при запросах к базе данных
    #40116602
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
Где можно создать issue с этой проблемой? Разработчик Nuget для Oracle.ManagedDataAccess.Core 3.21.4, или саппорт Oracle?

https://www.nuget.org/packages/Oracle.ManagedDataAccess.Core/
Справа внизу см. ссылки Owners и Contact owners
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Чрезмерное использование RAM при запросах к базе данных
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]