This document discusses ways to improve application performance for a project involving 5 developers and 1 tester building a web, desktop, and mobile application over 18 sprints using .NET and SQL Server. It recommends preparing the database with indexes, stored procedures, and filegroups; fine-tuning the production database; learning about Entity Framework best practices like using stored procedures and lazy loading; using caching; optimizing for RAM usage; logging configuration; and considering scalability, performance, and architecture in technical choices.
8. #1: Prepare the database
• INDEXES:
– Choose the indexes wisely
– Use multi-column indexes
• Pay attention to the order of the columns
– Use Filtered Indexes
– Use Included Columns
• Use Stored Procedures for the most data intensive
features
– And spend some time optimizing those!
• Avoid unnecessary LOCKs
– Use WITH(NOLOCK) on tables that allow READ UNCOMMITED
9. #2: Fine tune the PROD database
• FILEGROUPS:
– Separate tables and indexes into different
FILEGROUPS
– Isolate large tables on different FILEGROUPS
• Hard drives:
– Allocate fastest harddrives to indexes and
mission critical tables
– Make sure the tempdb is on the fastest storage
possible
11. #3: Learn about Entity Framework
• Use Stored Procedures for critical reads
• Use Complex Types for Slim classes
– Results for Search or List operations
• LINQ clauses: Beware the order
// SELECT * FROM [Table] ; Count is performed in memory
Where().ToList().Count()
VS
// SELECT COUNT(*) FROM [Table]
Where().Count()
12. #4: Beware of lazy loading
using (var context = new DbContext())
{
// SELECT * from Messages WHERE ID = @messageId
var message = context.Messages.SingleOrDefault(m => m.ID == messageId);
// SELECT * FROM User WHERE ID = @message.ToUserFK
var toUser = message.ToUser;
// Now imagine this on a loop...
}
Vs
using (var context = new DbContext())
{
// SELECT * FROM Messages INNER JOIN Users ON (...)
var message = context.Messages
.Include("ToUser")
.SingleOrDefault(m => m.ID == messageId);
}
13. #5: Use SQL Parameters on
queries
• Use SqlParameters on ADO.NET queries
– Avoid string concatenation to build query
string command = String.Format("SELECT * FROM Message WHERE FromUserFK = {0}",
fromUserId);
Vs
SqlCommand command = new SqlCommand("SELECT * FROM Message WHERE FromUserFK =
@fromUserFk", connection);
command.Parameters.AddWithValue("@fromUserFK", fromUserId);
14. #6: Use cache
• Store data in Cache
– Reference tables
– Read-mostly data
– Recently read data
• Choose the most appropriate caching platform:
– Local Cache: MemCache
– Distributed Cache: Redis Cache, ...
• BUT...
– Measure the cost of querying the cache
15. #7: RAM is cheap, but...
• Avoid unnecessary data loads
– Especially large data blocks
• stateless objects should always be singleton
• Optimize your code
– Avoid the ‘+’ to concatenate strings Use
StringBuilder() or String.Format() instead
– Optimize the loops
– Avoid expensive operations
– Beware of serialization
16. #8: Mind the Logger
• Logging to Database causes LOCKs
And potential Exceptions on the application code
• Logging to disk causes contention
Unless configured otherwise
Log4net:
<appender>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
</appender>
17. #8: Mind the Logger
string[] operationResult = (...);
logger.Debug("The result of this long running is {0}", string.Join(operationResult,";"));
VS
if(logger.IsDebugEnabled)
{
logger.Debug(" The result of this long running is {0}", string.Join(operationResult,";"));
}
string.Join() will always be
executed, even if DEBUG is
disabled
18. #9: Misc.
• Class mapping
– Auto mapping (reflection) vs Manual mapping
• Exception handling
– Minimize catch() statements
– Exceptions must flow as much as possible
– Only catch exceptions on methods in case of adding
some value to it:
Retry
Handle the error and proceed
× Logging and rethrow
19. At the end of the day
Scalability
Performance
Features & User Experience
Costs of technical choices
Dev effort and time
Solution Architecture
IT Hardware
Benefits of technical choices