From 0c270b145a5ed1ee4b1cefdea9b88a81c26d5d0a Mon Sep 17 00:00:00 2001 From: Joshua Duscha Date: Sun, 5 Nov 2023 19:10:34 +0100 Subject: [PATCH 1/4] Update to .net 8 --- OptimizeMePlease.csproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OptimizeMePlease.csproj b/OptimizeMePlease.csproj index f603ecd..15c4650 100644 --- a/OptimizeMePlease.csproj +++ b/OptimizeMePlease.csproj @@ -2,20 +2,20 @@ Exe - netcoreapp3.1 + net8.0 - + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 8a577bb45b2294c7ba021464411aaf41b0c5353b Mon Sep 17 00:00:00 2001 From: Joshua Duscha Date: Sun, 5 Nov 2023 19:40:07 +0100 Subject: [PATCH 2/4] Add docker-compose.yml --- docker-compose.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b39564d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: "3.9" + +services: + db: + image: "mcr.microsoft.com/mssql/server:2022-latest" + user: root + environment: + ACCEPT_EULA: "Y" + SA_PASSWORD: "test@123" + volumes: + - db_vol:/var/opt/mssql/data + ports: + - "1433:1433" + +volumes: + db_vol: {} \ No newline at end of file From 7d99d935b4197535a8141cc31e0a4915f35dafd1 Mon Sep 17 00:00:00 2001 From: Joshua Duscha Date: Sun, 5 Nov 2023 19:40:28 +0100 Subject: [PATCH 3/4] Update Connection String --- Context/AppDbContext.cs | 2 +- Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Context/AppDbContext.cs b/Context/AppDbContext.cs index dc14c8a..0541e24 100644 --- a/Context/AppDbContext.cs +++ b/Context/AppDbContext.cs @@ -9,7 +9,7 @@ public class AppDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder options) { - options.UseSqlServer("Server=localhost;Database=OptimizeMePlease;Trusted_Connection=True;Integrated Security=true;MultipleActiveResultSets=true"); + options.UseSqlServer("Server=localhost,1433;Database=OptimizeMePlease;TrustServerCertificate=True;User Id=sa;Password=test@123;MultipleActiveResultSets=true"); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/Program.cs b/Program.cs index c557a59..b1f6390 100644 --- a/Program.cs +++ b/Program.cs @@ -36,7 +36,7 @@ static void Main(string[] args) public static void IWillPopulateData() { - string sqlConnectionString = @"Server=localhost;Database=OptimizeMePlease;Trusted_Connection=True;Integrated Security=true;MultipleActiveResultSets=true"; + string sqlConnectionString = @"Server=localhost,1433;Database=OptimizeMePlease;TrustServerCertificate=True;User Id=sa;Password=test@123;MultipleActiveResultSets=true"; string workingDirectory = Environment.CurrentDirectory; string path = Path.Combine(Directory.GetParent(workingDirectory).Parent.Parent.FullName, @"script.sql"); From e4e5cfa97124f037d2020bf002930491066203f8 Mon Sep 17 00:00:00 2001 From: Joshua Duscha Date: Sun, 5 Nov 2023 21:45:35 +0100 Subject: [PATCH 4/4] Complete Query Optimization --- BenchmarkService.cs | 57 ++++++++++++++++++++++++++++++++++------- Context/AppDbContext.cs | 4 ++- Program.cs | 6 ++--- README.md | 4 +++ 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/BenchmarkService.cs b/BenchmarkService.cs index a32a5c8..c736d2b 100644 --- a/BenchmarkService.cs +++ b/BenchmarkService.cs @@ -11,20 +11,20 @@ namespace OptimizeMePlease { [MemoryDiagnoser] [HideColumns(BenchmarkDotNet.Columns.Column.Job, BenchmarkDotNet.Columns.Column.RatioSD, BenchmarkDotNet.Columns.Column.StdDev, BenchmarkDotNet.Columns.Column.AllocRatio)] - //[Config(typeof(Config))] + [Config(typeof(Config))] public class BenchmarkService { public BenchmarkService() { } - //private class Config : ManualConfig - //{ - // public Config() - // { - // SummaryStyle = BenchmarkDotNet.Reports.SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend); - // } - //} + private class Config : ManualConfig + { + public Config() + { + SummaryStyle = BenchmarkDotNet.Reports.SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend); + } + } /// /// Get top 2 Authors (FirstName, LastName, UserName, Email, Age, Country) @@ -32,7 +32,7 @@ public BenchmarkService() /// and all his/her books (Book Name/Title and Publishment Year) published before 1900 /// /// - [Benchmark] + [Benchmark(Baseline = true)] public List GetAuthors() { using var dbContext = new AppDbContext(); @@ -98,6 +98,45 @@ public List GetAuthors() return finalAuthors; } + // 1260x faster than GetAuthors() with this query + these indexes + // CREATE NONCLUSTERED INDEX idx_Books ON Books (AuthorId, Published) INCLUDE (Name) + // CREATE NONCLUSTERED INDEX idx_Author ON Authors (Age, BooksCount DESC) INCLUDE (Id, Country, UserId) + private static readonly Func> CompiledOptimized = + EF.CompileQuery((AppDbContext context) => context.Authors + .Where(x => x.Country == "Serbia" && x.Age == 27) + .OrderByDescending(x => x.BooksCount) + .Select(x => new AuthorDTO + { + UserFirstName = x.User.FirstName, + UserLastName = x.User.LastName, + UserEmail = x.User.Email, + UserName = x.User.UserName, + AuthorAge = x.Age, + AuthorCountry = x.Country, + AllBooks = x.Books.Where(b => b.Published.Year < 1900).Select(y => new BookDto + { + Name = y.Name, + Published = y.Published, + }).ToList() + }) + .Take(2)); + + /// + /// Get top 2 Authors (FirstName, LastName, UserName, Email, Age, Country) + /// from country Serbia aged 27, with the highest BooksCount + /// and all his/her books (Book Name/Title and Publishment Year) published before 1900 + /// + /// + [Benchmark] + public List GetAuthors_Optimized() + { + using var dbContext = new AppDbContext(); + + var authors = CompiledOptimized(dbContext).ToList(); + + return authors; + } + //[Benchmark] //public List GetAuthors_Optimized() //{ diff --git a/Context/AppDbContext.cs b/Context/AppDbContext.cs index 0541e24..dd63e73 100644 --- a/Context/AppDbContext.cs +++ b/Context/AppDbContext.cs @@ -9,7 +9,9 @@ public class AppDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder options) { - options.UseSqlServer("Server=localhost,1433;Database=OptimizeMePlease;TrustServerCertificate=True;User Id=sa;Password=test@123;MultipleActiveResultSets=true"); + options.UseSqlServer( + "Server=localhost,1433;Database=OptimizeMePlease;TrustServerCertificate=True;User Id=sa;Password=test@123;MultipleActiveResultSets=true") + /*.LogTo(s => { Console.WriteLine(s); }, LogLevel.Information)*/; } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/Program.cs b/Program.cs index b1f6390..efbe192 100644 --- a/Program.cs +++ b/Program.cs @@ -24,9 +24,9 @@ public class Program static void Main(string[] args) { //Debugging - //BenchmarkService benchmarkService = new BenchmarkService(); - //var p = benchmarkService.GetAuthors_Optimized_Struct(); - //var d = benchmarkService.GetAuthors_Optimized_Struct1(); + BenchmarkService benchmarkService = new BenchmarkService(); + // var d = benchmarkService.GetAuthors(); + // var p = benchmarkService.GetAuthors_Optimized(); //Comment me after first execution, please. //IWillPopulateData(); diff --git a/README.md b/README.md index 4982f83..677bc6f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # OptimizeMePlease +# Docker Compose + +- Run `docker-compose up -d` to start the database + ## You are probably here because you saw my post on Linkedin. ## Welcome!