Medio Ambiente:ADO.Net SqlCommand.ExecuteReader() se ralentiza o se cuelga
Aplicación (escrito en C# para .Net 4) tiene hasta 10 hilos, cada hilo ejecuta en su propio dominio de aplicación. Cada subproceso usa un ADO.Net DataReader que obtiene los resultados del procedimiento almacenado en SQL-Server 2008. También un subproceso puede usar ADO.Net para realizar una operación de escritura (inserción masiva). Todo se ejecuta en la máquina local.
Problema # 1:
Ocasionalmente (aproximadamente cada 30a run) ejecución de un subproceso ralentiza drásticamente. Eso ocurre cuando DataReader obtiene los resultados del procedimiento almacenado: SqlCommand.ExecuteReader(). Por lo general, la operación de lectura se ejecuta en 10 segundos. Cuando se ralentiza, se ejecuta en 10-20 minutos. SQLProfiler muestra que los datos se están consultando, aunque muy lentamente.
pila de llamadas de la desaceleración (tenga en cuenta que no hay excepciones):
at SNIReadSync(SNI_Conn* , SNI_Packet** , Int32)
at SNINativeMethodWrapper.SNIReadSync(SafeHandle pConn, IntPtr& packet, Int32 timeout)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
at System.Data.SqlClient.TdsParserStateObject.ReadByteArray(Byte[] buff, Int32 offset, Int32 len)
at System.Data.SqlClient.TdsParserStateObject.ReadString(Int32 length)
at System.Data.SqlClient.TdsParser.ReadSqlStringValue(SqlBuffer value, Byte type, Int32 length, Encoding encoding, Boolean isPlp, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ReadColumnData()
at System.Data.SqlClient.SqlDataReader.ReadColumnHeader(Int32 i)
at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32 i)
at System.Data.SqlClient.SqlDataReader.GetValue(Int32 i)
at System.Data.SqlClient.SqlDataReader.get_Item(String name)
at ****.Core.TableDataImporter.ImportDataFromExcel(Int32 tableId, ExcelEntityLocation location, Boolean& updateResult) in …
Problema # 2:
En lugar de una ralentización un hilo puede colgar.
pila de llamadas:
at SNIReadSync(SNI_Conn* , SNI_Packet** , Int32)
at SNINativeMethodWrapper.SNIReadSync(SafeHandle pConn, IntPtr& packet, Int32 timeout)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
at System.Data.SqlClient.TdsParserStateObject.ReadByte()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
callstacks fueron adquiridas utilizando herramientas de depuración en el hilo de fondo. No hay excepciones, ya sea una desaceleración o colgando.
SNIReadSync es un mecanismo que funciona a nivel de red y trabaja con la transmisión de paquetes a través de la red. Hemos reproducido este problema en la máquina local, eliminando los problemas de red de la ecuación.
Estamos buscando cualquier entrada y soluciones o soluciones para estas ralentizaciones/cuelgues. Por ahora planeamos detectar la ralentización y volver a ejecutar la operación. Gracias por adelantado.
estoy añadiendo código simplificado para el método conforme a lo solicitado:
public void ImportDataFromExcel()
{
try
{
var _сonnectionBuilk = ... ; // singleton connection (at the app level)
var spName = ... ; // stored procedure name
var сonnectionToRead = new SqlConnection(connectionStirng);
сonnectionToRead.Open();
var sqlCommand = new SqlCommand(spName);
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add(param1Name, SqlDbType.Int).Value = ...;
sqlCommand.Parameters.Add(param2Name, SqlDbType.Int).Value = ...;
sqlCommand.Parameters.Add(param2Name, SqlDbType.Int).Value = ...;
sqlCommand.Connection = сonnectionToRead;
sqlCommand.CommandTimeout = timeout; // 120 sec
using (var dataReader = sqlCommand.ExecuteReader())
{
dataReader.Read();
.....
int pos1 = dataReader.GetOrdinal(columnName1);
int pos2 = dataReader.GetOrdinal(columnName2);
int pos3 = dataReader.GetOrdinal(columnName3);
int pos4 = dataReader.GetOrdinal(columnName4);
.....
// reading data from sqldatareader
int val1 = dataReader.GetInt32(pos1);
int val2 = dataReader.GetInt32(pos2);
int val3 = dataReader.GetInt32(pos3);
var val4 = dataReader.GetDateTime(pos4);
.....
// append read data into bulkTable
bulkTable.AddCellValue(val1, val2, val3, val4); // bulkTable wraps DataTable, and appends DataRow inside.
if(bulkTable.DataTable.Rows > MaxRowsCount)
{
using (var bulkCopy = new SqlBulkCopy(_сonnectionBuilk))
{
bulkCopy.DestinationTableName = _fullTableName;
bulkCopy.WriteToServer(bulkTable.DataTable);
}
var sqlCommandTransfer = new SqlCommand(spName);
sqlCommandTransfer.CommandType = CommandType.StoredProcedure;
sqlCommandTransfer.Parameters.Add(param1Name, SqlDbType.Int).Value = ...;
sqlCommandTransfer.Connection = _сonnectionBuilk;
....
sqlCommandTransfer.ExecuteNonQuery(); // transfering data from temp bulk table into original table
}
}
}
finally
{
bulkTable.Dispose();
сonnectionToRead.Close();
}
}
¿Puede mostrar el código? Especialmente cuando estás creando, abriendo, cerrando la conexión y ejecutando el lector. –
Eso suena más como un problema en el lado db. ¿Hay algún proceso de trabajo en SQL que se ejecute periódicamente? ¿Una Sincronización o alguna acción que está causando un bloqueo de fila/tabla? ¿Qué tan grandes son las tablas involucradas? qué tipo de índices/restricciones, etc. – Brian
@TimSchmelter - He agregado un código que se cuelga. – Cortlendt