├── libs └── Restuta.ConsoleExtensions.dll ├── Mongo.Guid-vs-ObjectId ├── packages.config ├── App.config ├── MongoExtensions.cs ├── Measure.cs ├── Properties │ └── AssemblyInfo.cs ├── Mongo.Guid-vs-ObjectId.csproj └── Program.cs ├── Mongo.Guid-vs-ObjectId.sln ├── .gitignore └── README.md /libs/Restuta.ConsoleExtensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Restuta/mongo.Guid-vs-ObjectId-performance/HEAD/libs/Restuta.ConsoleExtensions.dll -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/MongoExtensions.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Driver; 2 | 3 | namespace Mongo.Guid_vs_ObjectId 4 | { 5 | public static class MongoExtensions 6 | { 7 | /// 8 | /// Gets typed mongo collection using given generic type and type name as a collection name. 9 | /// 10 | public static MongoCollection GetCollection(this MongoDatabase db) 11 | { 12 | return db.GetCollection(typeof(T).Name); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mongo.Guid-vs-ObjectId", "Mongo.Guid-vs-ObjectId\Mongo.Guid-vs-ObjectId.csproj", "{22F279C1-B8F0-44EB-BA8A-DEEC4FE72358}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {22F279C1-B8F0-44EB-BA8A-DEEC4FE72358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {22F279C1-B8F0-44EB-BA8A-DEEC4FE72358}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {22F279C1-B8F0-44EB-BA8A-DEEC4FE72358}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {22F279C1-B8F0-44EB-BA8A-DEEC4FE72358}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/Measure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Mongo.Guid_vs_ObjectId 5 | { 6 | public static class Measure 7 | { 8 | public static long LastMeasurmentTime { get; set; } 9 | 10 | private static readonly System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); 11 | 12 | /// 13 | /// Will be executed at the end of each performance measurement, by default writes elapsed ms to Console 14 | /// 15 | public static Action WhenDone = (prefix, elapsedTime) => Console.WriteLine(elapsedTime + "ms"); 16 | 17 | public static void Performance(Action codeToMeasure, string prefix = "") 18 | { 19 | stopwatch.Reset(); 20 | stopwatch.Start(); 21 | 22 | codeToMeasure.Invoke(); 23 | 24 | stopwatch.Stop(); 25 | 26 | var elapsedMilliseconds = stopwatch.ElapsedMilliseconds; 27 | 28 | WhenDone.Invoke(prefix, elapsedMilliseconds); 29 | LastMeasurmentTime = elapsedMilliseconds; 30 | } 31 | 32 | 33 | public static void Performance(string prefix, Action codeToMeasure) 34 | { 35 | Performance(codeToMeasure, prefix); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Mongo.Guid-vs-ObjectId")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Mongo.Guid-vs-ObjectId")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c58030ae-41bd-431f-9ded-bd9ca183c99b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/Mongo.Guid-vs-ObjectId.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {22F279C1-B8F0-44EB-BA8A-DEEC4FE72358} 8 | Exe 9 | Properties 10 | Mongo.Guid_vs_ObjectId 11 | Mongo.Guid-vs-ObjectId 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\mongocsharpdriver.1.7.1\lib\net35\MongoDB.Bson.dll 37 | 38 | 39 | ..\packages\mongocsharpdriver.1.7.1\lib\net35\MongoDB.Driver.dll 40 | 41 | 42 | ..\libs\Restuta.ConsoleExtensions.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 70 | -------------------------------------------------------------------------------- /Mongo.Guid-vs-ObjectId/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MongoDB.Bson; 7 | using MongoDB.Bson.Serialization.Attributes; 8 | using MongoDB.Bson.Serialization.IdGenerators; 9 | using MongoDB.Driver; 10 | using MongoDB.Driver.Linq; 11 | using Restuta.ConsoleExtensions.Colorfull; 12 | 13 | namespace Mongo.Guid_vs_ObjectId 14 | { 15 | internal delegate void Write(ColorfullString colorfullString); 16 | internal delegate void WriteLine(ColorfullString colorfullString); 17 | 18 | public class TestDocument 19 | { 20 | [BsonId(IdGenerator = typeof(GuidGenerator))] 21 | public Guid Id { get; set; } 22 | } 23 | 24 | class Program 25 | { 26 | static readonly Write W = ColorfullConsole.Write; 27 | static readonly WriteLine WL = ColorfullConsole.WriteLine; 28 | 29 | 30 | static void Main(string[] args) 31 | { 32 | Measure.WhenDone = (prefix, time) => WL(prefix.ToString().DarkCyan() + " time: " + (time.ToString() + "ms").DarkYellow()); 33 | 34 | const int NumberOfDocuments = 10000000; 35 | var db = GetDatabase(); 36 | 37 | Measure.Performance(NumberOfDocuments + " documents insertion with", () => 38 | { 39 | foreach (var document in NewTestDocument().Take(NumberOfDocuments)) 40 | { 41 | db.GetCollection().Insert(document); 42 | } 43 | }); 44 | WL((Measure.LastMeasurmentTime / Convert.ToDouble(NumberOfDocuments)).ToString() + "ms per document"); 45 | 46 | //Measure.Performance(NumberOfDocuments + " BATCH documents insertion with", () => 47 | //{ 48 | // db.GetCollection().InsertBatch(NewTestDocument().Take(NumberOfDocuments)); 49 | //}); 50 | //WL((Measure.LastMeasurmentTime / Convert.ToDouble(NumberOfDocuments)).ToString() + "ms per document"); 51 | 52 | Measure.Performance("Skip 10 000 000 docs and take one", () => 53 | { 54 | var doc = db.GetCollection().AsQueryable().Skip(10000000).Take(1).ToList().SingleOrDefault(); 55 | WL(doc.Id.ToString()); 56 | }); 57 | 58 | Measure.Performance("Reading one document by id", () => 59 | { 60 | var doc = db.GetCollection().AsQueryable().SingleOrDefault(x => x.Id == new Guid("2dbe6ee1-42b7-4209-8c84-cb2fbe6a799c")); 61 | WL(doc.Id.ToString()); 62 | }); 63 | 64 | //Measure.Performance("Count doc's grater than random Id", () => 65 | //{ 66 | // var doc = db.GetCollection().AsQueryable().Count(x => x.Id >= new Guid("2dbe6ee1-42b7-4209-8c84-cb2fbe6a799c")); 67 | // WL(doc.ToString()); 68 | //}); 69 | 70 | } 71 | 72 | private static MongoDatabase GetDatabase() 73 | { 74 | var testDbConnStrBuilder = new MongoUrlBuilder("mongodb://localhost/Guid-vs-ObjectId?safe=true"); 75 | var connectionString = testDbConnStrBuilder.ToMongoUrl(); 76 | var client = new MongoClient(connectionString); 77 | var mongoDatabase = client.GetServer().GetDatabase(connectionString.DatabaseName); 78 | 79 | mongoDatabase.SetProfilingLevel(ProfilingLevel.All); 80 | return mongoDatabase; 81 | } 82 | 83 | 84 | public static IEnumerable NewTestDocument() 85 | { 86 | while (true) 87 | { 88 | yield return new TestDocument(); 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mongo.Guid-vs-ObjectId-performance 2 | ================================== 3 | Comparing index performance on using Guids and ObjectIds with Mongo 4 | 5 | I have always been told that non-sequential ids lead to drop in index performance, therefore I decided to test it. 6 | It's interesting to understand what percent of perfomance drop we are talking about. So I've chosen `ObjectId` as a highly sequential id and `Guid` as non-sequential one. 7 | 8 | **Update:** According to my tests I can't notice any significant perfomance difference in reads, there is some on the write side, could you please advice what I am doing wrong? What test cases should I try to execute and compare? 9 | 10 | 11 | 12 | Each test was performed at least 3 times. 13 | 14 | **Tip:** There are several branches, each for each test-set (guid, objectId, etc). 15 | 16 | 17 | | | ObjectId | Guid | Sequential Guid|% perf drop1| 18 | | --------------------------------------------------------|:-------------:|:----------------:|:---:|:--:| 19 | | 1M inserts batched | 13,401ms | 37,138ms |39,291ms|177%| 20 | | 1M inserts | 133,255ms | 160,199ms |159,393ms|20%| 21 | | 10m inserts batched, with 10M documents already present | 152,426ms | 470,489ms |482,354ms|200%| 22 | | 10m inserts, with 10M documents already present | 1,337,894ms | 4,921,991ms ||268%| 23 | | Find document by id (24M docs) | 25ms | 25ms |22ms|0%| 24 | | Skip 10M docs, take 1 (24M docs) | 1,401ms | 1,454ms |1,449ms|3.8%| 25 | | Count docs where doc.id > randomId (24M docs) | 48,363ms |not applicable (since operator ">") doesn't work for Guid|| 26 | |Index size for 24M docs | 819MB | 1225MB |50%| 27 | 28 | 1 percent of performance drop is calculated `guid / objectid - 100` since objectId is a baseline 29 | 30 | 31 | ----------------------------------- 32 | Raw results to be analysed later 33 | ================================ 34 | ObjectId 35 | ``` 36 | docs inserted during past 60 seconds:0 37 | docs inserted during past 60 seconds:3813220 38 | docs inserted during past 60 seconds:3813220 39 | docs inserted during past 60 seconds:4575864 40 | docs inserted during past 60 seconds:3813220 41 | docs inserted during past 60 seconds:4575864 42 | docs inserted during past 60 seconds:3813220 43 | docs inserted during past 60 seconds:3050576 44 | docs inserted during past 60 seconds:4575864 45 | docs inserted during past 60 seconds:3813220 46 | docs inserted during past 60 seconds:4575864 47 | docs inserted during past 60 seconds:3813220 48 | docs inserted during past 60 seconds:3813220 49 | docs inserted during past 60 seconds:3813220 50 | docs inserted during past 60 seconds:3813220 51 | docs inserted during past 60 seconds:3050576 52 | docs inserted during past 60 seconds:3813220 53 | docs inserted during past 60 seconds:3813220 54 | docs inserted during past 60 seconds:4575864 55 | docs inserted during past 60 seconds:3050576 56 | docs inserted during past 60 seconds:3050576 57 | docs inserted during past 60 seconds:3813220 58 | docs inserted during past 60 seconds:3813220 59 | docs inserted during past 60 seconds:3813220 60 | docs inserted during past 60 seconds:1525288 61 | docs inserted during past 60 seconds:3050576 62 | docs inserted during past 60 seconds:3813220 63 | docs inserted during past 60 seconds:3050576 64 | 100000000 BATCH documents insertion with time: 1628639ms 65 | 0.01628639ms per document 66 | docs inserted during past 60 seconds:93636 67 | 5139193d932bdc5e346ff3a7 68 | Skip 10 000 000 docs and take one time: 11075ms 69 | Reading one document by id time: 421ms //not so true, other test proved that avg is ~42ms 70 | ``` 71 | --------------------------------------------------------------------------------