API ocasionalmente se ralentiza en tiempo de ejecución, posiblemente debido a SQL / Conexiones -- # campo con performance campo con sql camp codereview Relacionados El problema

Api occasionally slows down at runtime, possibly due SQL/connections


2
vote

problema

Español

Actualmente estoy trabajando en una API que se comporta increíblemente impredecible en tiempo de ejecución. Contexto: Corremos la misma llamada 100 veces sin demora en el medio. Una llamada puede tomar en cualquier lugar desde ~ 200 ms a ~ 5 segundos . Por lo general, se acumula "gradualmente y baja rápidamente después de aproximadamente medio minuto. Este problema solo ocurre en unos pocos entornos / bases de datos seleccionadas. No reproducible en las máquinas de desarrollo local.

Inicialmente el techo fue de unos 10 segundos. Después de algunas refactorizaciones, haciendo que todo funcione sin problemas en Async, hemos logrado reducir las llamadas API largas a ~ 5 segundos. El código relevante se pega a continuación, la clase 1.

Para el registro, el código funciona. Ocasionalmente, he dejado fuera un código y reemplaza con ... porque no es relevante.

  public async Task<Schedule> Get(Guid id) {   var templateInfoRecords = TemplateInfoRecords(id);   var scheduleDayInfoRecords = ScheduleDayInfos(id);    var resultTemplateInfos = new List<ScheduleTemplateInfo>();    foreach (var record in await templateInfoRecords.ConfigureAwait(false)) {     int scheduleTemplateId = record.TMPLDAY_ID;     int scheduleTemplateStartoffset = record.TMPLDAY_STARTOFFSET;     int scheduleTemplateCyclenumber = record.TMPLDAY_CYCLENUMBER;     int scheduleTemplateNumber = record.TMPLDAY_DAYNUMBER;     var dayOfWeek = (DayOfWeek)(scheduleTemplateNumber - 1);     DateTime? tmpldayEnddate = record.TMPLDAY_ENDDATE;     DateTime tmpldayStartdate = record.TMPLDAY_STARTDATE;     DateTime tmpldayCreation = record.TMPLDAY_CREATION;      var sessions = FillUpSessionsAsync(record, scheduleTemplateId);      resultTemplateInfos.Add(new ScheduleTemplateInfo(       record.Id,       tmpldayCreation,       new PeriodOfApplicability(new ScheduleTemplatePeriod(tmpldayStartdate, tmpldayEnddate), dayOfWeek,         scheduleTemplateCyclenumber.ToScheduleTemplateRecurrencePattern(scheduleTemplateStartoffset)),       await sessions.ConfigureAwait(false)));   }    return new Schedule(resultTemplateInfos, await scheduleDayInfoRecords.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo[]> FillUpSessionsAsync(dynamic record, int scheduleTemplateId) {   var sessionsTasks = new List<Task<ScheduleTemplateSessionInfo>>(3);    if (record.TMPLDAY_START1 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo1(record, scheduleTemplateId));   }   if (record.TMPLDAY_START2 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo2(record, scheduleTemplateId));   }   if (record.TMPLDAY_START3 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo3(record, scheduleTemplateId));   }    await Task.WhenAll(sessionsTasks.ToArray()).ConfigureAwait(false);    return sessionsTasks.Select(sessionsTask => sessionsTask.Result).ToArray(); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo1(dynamic record, int scheduleTemplateId) {   var session1ProgramRecords = GetPrograms(scheduleTemplateId, record.TMPLDAY_START1, record.TMPLDAY_END1);   var session1StaffRecords = GetStaff(scheduleTemplateId, 1);    return new ScheduleTemplateSessionInfo(..., await session1ProgramRecords.ConfigureAwait(false), ...,     await session1StaffRecords.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo2(dynamic record, int scheduleTemplateId) {   var session2Programs = this.GetPrograms(scheduleTemplateId, record.TMPLDAY_START2, record.TMPLDAY_END2);   var session2Staff = GetStaff(scheduleTemplateId, 2);    return new ScheduleTemplateSessionInfo(..., await session2Programs.ConfigureAwait(false),     ...., await session2Staff.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo3(dynamic record, int scheduleTemplateId) {   var session3Programs = this.GetPrograms(scheduleTemplateId, record.TMPLDAY_START3, record.TMPLDAY_END3);   var session3Staff = GetStaff(scheduleTemplateId, 3);    return new ScheduleTemplateSessionInfo(..., await session3Programs.ConfigureAwait(false),     ...., await session3Staff.ConfigureAwait(false)); }    private async Task<IEnumerable<dynamic>> TemplateInfoRecords(Guid id) {   using (var db = _dbConnectionFactory.OpenConnection()) {     return await db.QueryAsync(       "SELECT " +       " ... 50+ records ... " +       "FROM [dbo].[TEMPLATE_DAY] " +       "JOIN [dbo].[RESOURCE] ON [dbo].[RESOURCE].RSC_ID = [dbo].[TEMPLATE_DAY].RSC_ID " +       "JOIN [dbo].[LOCATION] Session1Location ON Session1Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC_ID " +       "JOIN [dbo].[LOCATION] Session2Location ON Session2Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC_LOC_ID " +       "JOIN [dbo].[LOCATION] Session3Location ON Session3Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC2_LOC_ID " +       "JOIN [dbo].[NOTE] Session1Note ON Session1Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOTE_ID " +       "JOIN [dbo].[NOTE] Session2Note ON Session2Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOT_NOTE_ID " +       "JOIN [dbo].[NOTE] Session3Note ON Session3Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOT2_NOTE_ID " +       "WHERE [dbo].[RESOURCE].Id = @id ", new { id }).ConfigureAwait(false);   } }    private async Task<IEnumerable<ScheduleDayInfo>> ScheduleDayInfos(Guid scheduleId) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query = "SELECT DISTINCT(SCHDP_DATE) AS Date, [dbo].[RESOURCE].Id FROM [dbo].[SCHEDULE_DPART] " +                           "JOIN [dbo].[RESOURCE] ON [dbo].[RESOURCE].RSC_ID = [dbo].[SCHEDULE_DPART].RSC_ID " +                           "WHERE [dbo].[RESOURCE].Id = @id AND SCHEDULE_DPART.SCHDP_TYPE IN ('N', 'S') " +                           "AND [dbo].[SCHEDULE_DPART].SCHDP_DATE >= CONVERT(date, GETDATE())";     return       (await db.QueryAsync(query, new { id = scheduleId }).ConfigureAwait(false))         .Select(record => new ScheduleDayInfo(ScheduleDayGuidProvider.Generate(record.Id, record.Date), record.Date));   } }    private async Task<ScheduleTemplateInfoSessionProgram[]> GetPrograms(int templateDayId, int sessionStartTime, int sessionEndTime) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query = "SELECT " +                           "...13 columns, mostly text, numbers and BIT converts ..." +                           "FROM [dbo].[TEMPLATE_PROGRAM] " +                           "JOIN [dbo].[NOTE] ON [NOTE].[NOTE_ID] = [TEMPLATE_PROGRAM].[NOTE_ID] " +                           "WHERE [TMPLDAY_ID] = @templateDayId AND [TMPLPRG_STARTTIME] >= @sessionStartTime AND [TMPLPRG_ENDTIME] <= @sessionEndTime";      var parameters = new {       templateDayId,       sessionStartTime,       sessionEndTime     };     return       (await db.QueryAsync(query, parameters).ConfigureAwait(false))         .Select(record => new ScheduleTemplateInfoSessionProgram((int?)record.Id, ..., (bool)record.PublishSlots, ...).ToArray();   } }    private async Task<int[]> GetStaff(int scheduleTemplateIntId, int sequenceNumber) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query =       "SELECT [CPS_ID] FROM [dbo].[TEMPLATE_DAY_STAFF]            WHERE [TMPLDAY_ID] = @scheduleTemplateIntId AND [TMPLDAY_DAYPART_NR] = @sequenceNumber";      var parameters = new {       scheduleTemplateIntId,       sequenceNumber     };      return (await db.QueryAsync<int>(query, parameters).ConfigureAwait(false)).ToArray();   } }   

¿Estamos haciendo algún error obvio / horrible aquí? Estoy bastante seguro de que ya estamos utilizando el async & amp; await Operadores bastante eficientes. Estoy empezando a pensar que esto podría ser una cosa externa que está causando los picos en retrasos. ¿No está relacionado con la codificación?

Original en ingles

I'm currently working on an API that behaves incredibly unpredictable at runtime. Context: We run the same call 100 times without delay in between. A call can take anywhere from ~200 ms to ~5 seconds. Usually it 'builds up' gradually and drops down quickly after about half a minute. This problem only occurs on a select few environments/databases. Not reproducable on local dev machines.

Initially the ceiling was about 10 seconds. After some refactoring already, making everything work smoothly in async, we have managed to reduce those long API calls to ~ 5 seconds. Relevant code is pasted below, all 1 class.

For the record, the code works. I've occasionally left out some code and replaces with ... because not relevant.

public async Task<Schedule> Get(Guid id) {   var templateInfoRecords = TemplateInfoRecords(id);   var scheduleDayInfoRecords = ScheduleDayInfos(id);    var resultTemplateInfos = new List<ScheduleTemplateInfo>();    foreach (var record in await templateInfoRecords.ConfigureAwait(false)) {     int scheduleTemplateId = record.TMPLDAY_ID;     int scheduleTemplateStartoffset = record.TMPLDAY_STARTOFFSET;     int scheduleTemplateCyclenumber = record.TMPLDAY_CYCLENUMBER;     int scheduleTemplateNumber = record.TMPLDAY_DAYNUMBER;     var dayOfWeek = (DayOfWeek)(scheduleTemplateNumber - 1);     DateTime? tmpldayEnddate = record.TMPLDAY_ENDDATE;     DateTime tmpldayStartdate = record.TMPLDAY_STARTDATE;     DateTime tmpldayCreation = record.TMPLDAY_CREATION;      var sessions = FillUpSessionsAsync(record, scheduleTemplateId);      resultTemplateInfos.Add(new ScheduleTemplateInfo(       record.Id,       tmpldayCreation,       new PeriodOfApplicability(new ScheduleTemplatePeriod(tmpldayStartdate, tmpldayEnddate), dayOfWeek,         scheduleTemplateCyclenumber.ToScheduleTemplateRecurrencePattern(scheduleTemplateStartoffset)),       await sessions.ConfigureAwait(false)));   }    return new Schedule(resultTemplateInfos, await scheduleDayInfoRecords.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo[]> FillUpSessionsAsync(dynamic record, int scheduleTemplateId) {   var sessionsTasks = new List<Task<ScheduleTemplateSessionInfo>>(3);    if (record.TMPLDAY_START1 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo1(record, scheduleTemplateId));   }   if (record.TMPLDAY_START2 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo2(record, scheduleTemplateId));   }   if (record.TMPLDAY_START3 > -1) {     sessionsTasks.Add(GetSessionScheduleTemplateSessionInfo3(record, scheduleTemplateId));   }    await Task.WhenAll(sessionsTasks.ToArray()).ConfigureAwait(false);    return sessionsTasks.Select(sessionsTask => sessionsTask.Result).ToArray(); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo1(dynamic record, int scheduleTemplateId) {   var session1ProgramRecords = GetPrograms(scheduleTemplateId, record.TMPLDAY_START1, record.TMPLDAY_END1);   var session1StaffRecords = GetStaff(scheduleTemplateId, 1);    return new ScheduleTemplateSessionInfo(..., await session1ProgramRecords.ConfigureAwait(false), ...,     await session1StaffRecords.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo2(dynamic record, int scheduleTemplateId) {   var session2Programs = this.GetPrograms(scheduleTemplateId, record.TMPLDAY_START2, record.TMPLDAY_END2);   var session2Staff = GetStaff(scheduleTemplateId, 2);    return new ScheduleTemplateSessionInfo(..., await session2Programs.ConfigureAwait(false),     ...., await session2Staff.ConfigureAwait(false)); }    private async Task<ScheduleTemplateSessionInfo> GetSessionScheduleTemplateSessionInfo3(dynamic record, int scheduleTemplateId) {   var session3Programs = this.GetPrograms(scheduleTemplateId, record.TMPLDAY_START3, record.TMPLDAY_END3);   var session3Staff = GetStaff(scheduleTemplateId, 3);    return new ScheduleTemplateSessionInfo(..., await session3Programs.ConfigureAwait(false),     ...., await session3Staff.ConfigureAwait(false)); }    private async Task<IEnumerable<dynamic>> TemplateInfoRecords(Guid id) {   using (var db = _dbConnectionFactory.OpenConnection()) {     return await db.QueryAsync(       "SELECT " +       " ... 50+ records ... " +       "FROM [dbo].[TEMPLATE_DAY] " +       "JOIN [dbo].[RESOURCE] ON [dbo].[RESOURCE].RSC_ID = [dbo].[TEMPLATE_DAY].RSC_ID " +       "JOIN [dbo].[LOCATION] Session1Location ON Session1Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC_ID " +       "JOIN [dbo].[LOCATION] Session2Location ON Session2Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC_LOC_ID " +       "JOIN [dbo].[LOCATION] Session3Location ON Session3Location.LOC_ID = [dbo].[TEMPLATE_DAY].LOC2_LOC_ID " +       "JOIN [dbo].[NOTE] Session1Note ON Session1Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOTE_ID " +       "JOIN [dbo].[NOTE] Session2Note ON Session2Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOT_NOTE_ID " +       "JOIN [dbo].[NOTE] Session3Note ON Session3Note.NOTE_ID = [dbo].[TEMPLATE_DAY].NOT2_NOTE_ID " +       "WHERE [dbo].[RESOURCE].Id = @id ", new { id }).ConfigureAwait(false);   } }    private async Task<IEnumerable<ScheduleDayInfo>> ScheduleDayInfos(Guid scheduleId) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query = "SELECT DISTINCT(SCHDP_DATE) AS Date, [dbo].[RESOURCE].Id FROM [dbo].[SCHEDULE_DPART] " +                           "JOIN [dbo].[RESOURCE] ON [dbo].[RESOURCE].RSC_ID = [dbo].[SCHEDULE_DPART].RSC_ID " +                           "WHERE [dbo].[RESOURCE].Id = @id AND SCHEDULE_DPART.SCHDP_TYPE IN ('N', 'S') " +                           "AND [dbo].[SCHEDULE_DPART].SCHDP_DATE >= CONVERT(date, GETDATE())";     return       (await db.QueryAsync(query, new { id = scheduleId }).ConfigureAwait(false))         .Select(record => new ScheduleDayInfo(ScheduleDayGuidProvider.Generate(record.Id, record.Date), record.Date));   } }    private async Task<ScheduleTemplateInfoSessionProgram[]> GetPrograms(int templateDayId, int sessionStartTime, int sessionEndTime) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query = "SELECT " +                           "...13 columns, mostly text, numbers and BIT converts ..." +                           "FROM [dbo].[TEMPLATE_PROGRAM] " +                           "JOIN [dbo].[NOTE] ON [NOTE].[NOTE_ID] = [TEMPLATE_PROGRAM].[NOTE_ID] " +                           "WHERE [TMPLDAY_ID] = @templateDayId AND [TMPLPRG_STARTTIME] >= @sessionStartTime AND [TMPLPRG_ENDTIME] <= @sessionEndTime";      var parameters = new {       templateDayId,       sessionStartTime,       sessionEndTime     };     return       (await db.QueryAsync(query, parameters).ConfigureAwait(false))         .Select(record => new ScheduleTemplateInfoSessionProgram((int?)record.Id, ..., (bool)record.PublishSlots, ...).ToArray();   } }    private async Task<int[]> GetStaff(int scheduleTemplateIntId, int sequenceNumber) {   using (var db = _dbConnectionFactory.OpenConnection()) {     const string query =       "SELECT [CPS_ID] FROM [dbo].[TEMPLATE_DAY_STAFF]            WHERE [TMPLDAY_ID] = @scheduleTemplateIntId AND [TMPLDAY_DAYPART_NR] = @sequenceNumber";      var parameters = new {       scheduleTemplateIntId,       sequenceNumber     };      return (await db.QueryAsync<int>(query, parameters).ConfigureAwait(false)).ToArray();   } } 

Are we making any obvious/horrible errors in here? I'm fairly sure we're already utilizing the async & await operaters fairly efficient. I'm starting to think this might be an external thing that's causing the spikes in delays. Unrelated to the coding?

        
       
       

Lista de respuestas


Relacionados problema

2  Implementación T-SQL TOTP (RFC6238 SHA2_256)  ( T sql totp rfc6238 sha2 256 implementation ) 
Usando mi Función anterior Como base que he subido lo siguiente: create function dbo.Totp ( @key varbinary(8000) , @timeStep int = 90 ) returns tab...

2  Análisis de datos de Big JSON Field y Geocode Services luego almacenar a PostgreSQL utilizando PsyCOPG2 en lugar de Django-ORM  ( Parsing data from big json field and geocode services then store to postgresql u ) 
Este código funciona, pero mi jefe me dijo que es un código muy malo, y no quiero desplegarlo. Es mi primera vez que trabaje como programador y tengo al menos...

2  Unirse interno solo si satisface si la condición  ( Inner join only if satisfies if condition ) 
Estoy buscando revisión de código, y optimizaciones. Tengo dos tablas ItemCategory y ShopItemCategory itemcategory ------------------------------...

10  Comparando datos en 2 tablas en diferentes servidores con suma de comprobación  ( Comparing data in 2 tables on different servers with checksum ) 
Así que he tenido un problema en el que necesito comparar datos en 2 tablas diferentes en dos servidores diferentes. Ahora, sé que MySQL admite CHECKSUM TABL...

5  Conseguir distinta de dos columnas  ( Get distinct of two columns ) 
Quiero obtener #ifndef __RUNES_MACROS_H #define __RUNES_MACROS_H #include <string.h> #include <constants.h> /* * Miscellaneous macros used by Runes */ ...

2  Dos guiones que completan la misma tarea, ¿cuál es la mejor manera?  ( Two script completing the same task which is the best way ) 
Tengo los siguientes dos métodos para completar la misma tarea, sin embargo, me gustaría saber que es el método preferido y por qué? o si hay alguna suger...

3  ¿Cuáles son los principales comentarios votados en las preguntas cerradas y que hicieron los comentarios?  ( What are the top voted comments on closed questions and who made the comments ) 
Siguiendo Esta pregunta vinculada y la retroalimentación que generó, coloco un nuevo consulta que utiliza un unión. 127.0.0.1/home/initialize/param1:va...

3  Análisis de errores de Oracle con una función KSH  ( Parsing oracle errors with a ksh function ) 
Hace algún tiempo escribí una pequeña rutina para ejecutar algunas consultas sucias rápidas (y con eso quiero decir que no se usa para consultas grandes) cont...

1  Un sistema similar / a diferencia de MySQL y PDO  ( A like unlike system using mysql and pdo ) 
He creado un sistema similar / a diferencia. El usuario hace clic en uno para indicar un "Me gusta" y hacer clic nuevamente para "A diferencia de". Actualment...

1  Devolver los IDS de los inicios de sesión fallidos  ( Return the ids of failed logins ) 
Tengo una consulta para devolver las ID de inicios de sesión fallidos que son más nuevos que una fecha suministrada, y también más reciente que el último inic...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos