├── 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 |
--------------------------------------------------------------------------------