Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Достигнут максимальный размер пула. Как можно найти причину  [new]
D_A_S1
Member

Откуда: Волгоград
Сообщений: 641
Добрый день!
Над проектом работало очень много людей, в итоге в последнее время стала очень часто возникать ошибка - Достигнут максимальный размер пула.
Можно ли как то средствами Sql Server понять где мы не закрываем подключение?
12 авг 18, 10:34    [21639051]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владимир Затуливетер
Member

Откуда:
Сообщений: 427
Попробуйте может поможет.
exec sys.sp_who2
--or
select
    er.session_id
  , ses.STATUS
  , ses.login_name
  , ses.host_name
  , er.blocking_session_id
  , db_name(er.database_id) as [db_name]
  , er.command
  , object_name(st.objectid) as object_name
  , er.cpu_time
  , er.start_time
  , cast(getdate() - er.start_time as time) as elapsed_time
  , st.text as query
from sys.dm_exec_requests er
    outer apply sys.dm_exec_sql_text(er.sql_handle) st
    left join sys.dm_exec_sessions ses on ses.session_id = er.session_id
    left join sys.dm_exec_connections con on con.session_id = ses.session_id
where er.session_id > 50


А вообще вам надо бы код клиента подправить.
В идеале у вас должен быть один общий метод который открывает соединение выполняет запрос и закрывает его. Его нужно использовать во всех DA методах.


Вот вам примерчик на C#, думаю идея понятна. (PS: код тут написал, так что может содержать ошибки.)
public static T ExecuteCommand(Func<SqlCommand,  T> action)
{
	using (var cnn = _cnnfactory.GetSqlClientConnection())
	using (var cmd = cnn.CreateCommand())
	{
		cnn.Open();
		
		return action(cmd);
		
		//cnn.Close(); вообще не обязательно явно закрывать соединение, будет вызван Dispose()
	}
}

public static List<T> ReadList<T>(this SqlCommand cmd, Func<DataReader, T> func)
{
	using (var reader = cmd.ExecuteReader())
	{
		var result = new List<T>();
		while (reader.Read())
		{
			result.Add(func(reader));
		}
		
		//reader.Close(); вообще не обязательно явно закрывать ридер, будет вызван Dispose()
		
		return result;
	}
}

// использование:
public List<Dto> GetSomeData()
{
	return ExecuteCommand(cmd => {
		cmd.CommandText = "select Id, Name from dbo.MyFavoriteTable";
		
		return cmd.ReadList(reader => new Dto {
			Id = reader.GetInt32("Id"),
			Name = reader.GetString("Name")
		});
	});
}
12 авг 18, 11:46    [21639091]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7746
D_A_S1,

емнип на C# клиенте надо вызывать не только клозе, но и дисконнект.
13 авг 18, 10:56    [21640037]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владимир Затуливетер
Member

Откуда:
Сообщений: 427
Владислав Колосов
D_A_S1,

емнип на C# клиенте надо вызывать не только клозе, но и дисконнект.

В каком классе и какой это метод?
13 авг 18, 11:25    [21640077]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31354
Владимир Затуливетер
//cnn.Close(); вообще не обязательно явно закрывать соединение, будет вызван Dispose()
Dispose будет автоматически вызван при вызове Finalize сборщиком мусора.
Вот так и получается превышение размера пула коннектов (или, если не повезёт, превышения не будет, но программа будет работать медленно).
документация
Always call Dispose before you release your last reference to the Component. Otherwise, the resources it is using will not be freed until the garbage collector calls the Component object's Finalize method.
Нужно всегда явно закрывать соединение. Или хотя бы явно вызвать Dispose

Владимир Затуливетер
В идеале у вас должен быть один общий метод который открывает соединение выполняет запрос и закрывает его. Его нужно использовать во всех DA методах.
Не то, что "в идеале", а абсолютно обязательно.
Это по моему понимает любой программист после первой написанной программы :-)
Потому что при малейшей правке приходится лазить по всему коду. Не говоря уже об ошибках из за описки или невнимательности.

Владислав Колосов
емнип на C# клиенте надо вызывать не только клозе, но и дисконнект.
Не, нету никакого "дисконнект", в классах доступа к БД это называется Close
13 авг 18, 11:30    [21640084]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Диклевич Александр
Member

Откуда:
Сообщений: 609
alexeyvg
Dispose будет автоматически вызван при вызове Finalize сборщиком мусора.


В интернетах пишут что это не так, и, цитирую
Eric J
The connection is disposed immediately after going out of scope of the using statement. That has nothing to do with garbage collection.
13 авг 18, 15:26    [21640676]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31354
Диклевич Александр
alexeyvg
Dispose будет автоматически вызван при вызове Finalize сборщиком мусора.


В интернетах пишут что это не так, и, цитирую
Eric J
The connection is disposed immediately after going out of scope of the using statement. That has nothing to do with garbage collection.
Не знаю, может, это в новых версиях так работает?
Я процитировал документацию к .NET Framework, версии 3.5, 3.0, 2.0, 1.1, 1.0
И сам видел описанное мной поведение, но давно, много лет назад, когда ещё писал на C#

А, вот, Владимир Затуливетер использует using, а для неё вызов Dispose гарантируется, это я не учёл.
13 авг 18, 15:58    [21640741]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владимир Затуливетер
Member

Откуда:
Сообщений: 427
Да, Close() не обязательно вызывать т.к. ипользуется using в приведенном коде.
13 авг 18, 17:11    [21640864]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
D_A_S1
Member

Откуда: Волгоград
Сообщений: 641
Подскажите, пожалуйста. Ищу, где могут быть проблемы.

У меня есть вот метод, который заполняет объекты класса:

using (var connection = DBModule.NewSqlConnection())
{
     var sql ="SELECT * FROM requestTransactions WHERE isDeleted = 0";
     return connection.Query<RequestTransaction>(sql).ToList();
}


Класс RequestTransaction имеет следующее:
 public class RequestTransaction
{
           [Key]
           public int id { get; set; }

          [Write(false)]
          public string fromOffice =>  this.fromOfficeId != null ? Office.GetById(this.fromOfficeId ?? 0)?.nameOffice : "";

}


Класс Office имеет следующее:
 public class Office
{
       public static Office GetById(int id) {
            using (var connection = DBModule.NewSqlConnection())
            {
                var sql = "SELECT * FROM dic_company_offices WHERE id = @id";
                return connection.QueryFirstOrDefault<Office>(sql, new { id });           
            }
        }

}


У меня вопрос: первоначальный метод использует свое подключение и заполняет список RequestTransaction. У каждого объекта RequestTransaction нужно определить офис, для этого используется метод, где также идет открытие своего подключения к БД.
В таком случае будут ли корректно закрываться соединения? Получается что одно соединение вложено в другое
16 авг 18, 12:36    [21644313]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7746
D_A_S1,

Вы пишете приложение для одного пользователя или многопользовательское? Один тип источника поступления данных или несколько?
По коду уже видно, что приложение будет затруднительно сопровождать и развивать как многопользовательское или неавтономное.
По вопросам C# Вам лучше обратиться на специализированный форум.
16 авг 18, 13:45    [21644463]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31354
D_A_S1
Подскажите, пожалуйста. Ищу, где могут быть проблемы.

У меня есть вот метод, который заполняет объекты класса:
Мы же не видим ваш код (может, конечно, на форуме C# разобрались бы...)
Что у вас за DBModule.NewSqlConnection? Что у него за метод такой, Query?
Типами щас вообще не пользуются, везде "var", как в бейсике :-)
В общем, по фрагменту непонятно, как это работает.

Вам писали, как себя ведут классы SqlConnection из System.Data.SqlClient, но что там у вас - непонятно.
И ещё, вам советовали, как избежать таких ошибок в принципе, потому что даже если в приведённом коде ошибки нет, то весь код приложения представляет из себя адскую лапшу, в которой может затесаться непонятно что.

По поводу правильности конкретно этого кода - в общем достаточно сделать тестовую функцию с вызовами вашего кода, и посмотреть на сиквеле профайлером, закрываются ли коннекты, или нет (точнее, возвращаются ли они в пул).
16 авг 18, 15:23    [21644653]     Ответить | Цитировать Сообщить модератору
 Re: Достигнут максимальный размер пула. Как можно найти причину  [new]
Владимир Затуливетер
Member

Откуда:
Сообщений: 427
public string fromOffice =>  this.fromOfficeId != null ? Office.GetById(this.fromOfficeId ?? 0)?.nameOffice : "";


Вот так не делайте, это вообще "кривой" подход.
На каждую вашу транзакцию (RequestTransaction) будете дергать Office.GetById.
Это очень тормознуто и затратно по ресурсам.

Вот так надо:
using (var connection = DBModule.NewSqlConnection())
{
     var sql = @"
select rt.*, o.nameOffice as fromOffice 
from requestTransactions rt
    left join dic_company_offices o on o.Id = rt.office_id
where rt.isDeleted = 0
";
     return connection.Query<RequestTransaction>(sql).ToList();
}

//и

public class RequestTransaction
{
           [Key]
           public int id { get; set; }

          [Write(false)]
          public string fromOffice { get; set; }
}
16 авг 18, 22:37    [21645114]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить