EF Core AddAsync and SaveChangesAsync slightly slower after application is idle for a long time

c# entity-framework-core


I am currently doing benchmark for my APIs and I noticed a bit delay on the first save operation using EF Core. The situation is after some period of inactivity (let's say 18 hours), the first save operation would take 1.5 seconds to execute, and subsequently, it is 100 ms at most. Below is a snippet of the code,

         public async Task SaveLog(Log log_item)
              // Set created and updated date/time
              log_item.created = DateTime.UtcNow;
              log_item.updated = DateTime.UtcNow;

              if (!(log_item.Month % 2 == 0))
              // Odd
                  var log_item_odd = log_item.ConvertLogToOdd();
                  await _dbContext.Log_Odd.AddAsync(log_item_odd);
              // Even
                  var log_item_even = log_item.ConvertLogToEven();
                  await _dbContext.Log_Even.AddAsync(log_item_even);

              await _dbContext.SaveChangesAsync();

Below are the execution time for this operation, as well as subsequent updates performed on the log that I captured, in ms.

[2018-12-29 06:25:00.199] [ADD_LOG] SaveLog 1556  
[2018-12-29 06:25:01.056] [UPDATE_LOG] UpdateLog 362  
[2018-12-29 06:27:13.652] [ADD_LOG] SaveLog 4  
[2018-12-29 06:27:13.886] [UPDATE_LOG] UpdateLog 9  
[2018-12-29 06:29:01.633] [ADD_LOG] SaveLog 4  
[2018-12-29 06:29:01.846] [UPDATE_LOG] UpdateLog 4  
[2018-12-29 06:56:21.544] [ADD_LOG] SaveLog 53  
[2018-12-29 06:56:21.996] [UPDATE_LOG] UpdateLog 5  
[2018-12-29 07:11:58.813] [ADD_LOG] SaveLog 94  
[2018-12-29 07:11:59.051] [UPDATE_LOG] UpdateLog 5  
[2018-12-29 07:16:12.241] [ADD_LOG] SaveLog 3  
[2018-12-29 07:16:12.639] [UPDATE_LOG] UpdateLog 4 

I could not find anything related to EF Core requiring some time to boot up after some period of inactivity, is there an explanation for this? *I am using PostgreSQL as the database.

Any help is appreciated, thank you.

12/29/2018 8:41:19 AM

Accepted Answer

Usually all providers have some implementations to prune idle connections after a period of idle time.

The first command takes a bit more time to create and open the connection. The next commands will use the pooled connection and they are faster. Then after being idle for a specific amount of time, providers prune the pool and close idle connections. Then the next command after idle time, needs to open a connection which again takes time.

For example for Npgsql, there is a PruneIdleConnectors in ConnectorPool which does the clean up based on the value of NpgsqlConnectionStringBuilder.ConnectionIdleLifetime which is 5 minutes by default. Here are related pooling parameters:

  • Connection Idle Lifetime: The time (in seconds) to wait before closing idle connections in the pool if the count of all connections exceeds MinPoolSize. Since 3.1 only. 300 seconds by default.
  • Connection Pruning Interval: How many seconds the pool waits before attempting to prune idle connections that are beyond idle lifetime (see ConnectionIdleLifetime). Since 3.1 only. 10 seconds by default.

For ADO.NET SqlConnection pooling this time is approximately 4-8 minutes:

The connection pooler removes a connection from the pool after it has been idle for approximately 4-8 minutes, or if the pooler detects that the connection with the server has been severed.

Note: It's already mentioned in comments as well, there are some other factors which may affect first execution time, including EF Context Pooling and Query Execution Plan cache in DBMS. But usually the most time-consuming of them is re-opening connection.

12/29/2018 10:02:07 AM

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow