Update performance is influenced by the similar factors as Insert Performance. The main factors include: configuration, disk access times, complexity of objects.
The following chapters provide some simple tests showing the influence of the above-mentioned factors. The test results are provided for Toshiba Sattelite Pro A120 notebook with 1,5Gb RAM 120GB ATA drive running on Vista and may be different on a different environment.
The following Item class is used in most of the tests:
UpdatePerformanceBenchmark.cs: Item private void Update(Object item) { objectContainer.Store(item); } // end Update private void RunDifferentObjectsTest() { System.Console.WriteLine("Update test with different objects"); int objectsToUpdate = 90; int updated = objectsToUpdate; InitDifferentObjectsTest(); Clean(); System.Console.WriteLine(" - primitive object with int field"); Open(Configure()); StoreSimplest(); IObjectSet result = objectContainer.QueryByExample(null); StartTimer(); for (int i = 0; i < objectsToUpdate; i++) { if (result.HasNext()) { SimplestItem item = (SimplestItem)result.Next(); item._id = 1; Update(item); } else { updated = i; break; } } StopTimer("Updated " + updated + " items"); Close(); Clean(); Open(Configure()); System.Console.WriteLine(" - object with string field"); Store(); updated = objectsToUpdate; result = objectContainer.QueryByExample(null); StartTimer(); for (int i = 0; i < objectsToUpdate; i++) { if (result.HasNext()) { Item item = (Item)result.Next(); item._name = "Updated"; Update(item); } else { updated = i; break; } } StopTimer("Updated " + updated + " items"); Close(); Clean(); Open(Configure()); System.Console.WriteLine(" - object with StringBuilder field"); StoreWithStringBuilder(); updated = objectsToUpdate; result = objectContainer.QueryByExample(null); StartTimer(); for (int i = 0; i < objectsToUpdate; i++) { if (result.HasNext()) { ItemWithStringBuilder item = (ItemWithStringBuilder)result.Next(); item._name = new StringBuilder("Updated"); Update(item); } else { updated = i; break; } } StopTimer("Updated " + updated + " items"); Close(); Clean(); Open(Configure()); System.Console.WriteLine(" - object with int array field"); StoreWithArray(); updated = objectsToUpdate; result = objectContainer.QueryByExample(null); StartTimer(); for (int i = 0; i < objectsToUpdate; i++) { if (result.HasNext()) { ItemWithArray item = (ItemWithArray)result.Next(); item._id = new int[] { 1, 2, 3 }; Update(item); } else { updated = i; break; } } StopTimer("Updated " + updated + " items"); Close(); Clean(); Open(Configure()); System.Console.WriteLine(" - object with ArrayList field"); StoreWithArrayList(); updated = objectsToUpdate; result = objectContainer.QueryByExample(null); StartTimer(); for (int i = 0; i < objectsToUpdate; i++) { if (result.HasNext()) { ItemWithArrayList item = (ItemWithArrayList)result.Next(); item._ids = new ArrayList(); Update(item); } else { updated = i; break; } } StopTimer("Updated " + updated + " items"); Close(); } // end RunDifferentObjectsTest private void RunIndexTest() { System.Console.WriteLine("Update test for objects with and without indexed fields"); int objectsToUpdate = 100; Init(); System.Console.WriteLine("Updating " + objectsToUpdate + " of " + _count + " objects"); Clean(); Open(Configure()); Store(); UpdateItems(objectsToUpdate); Close(); Clean(); Init(); System.Console.WriteLine("Updating " + objectsToUpdate + " of " + _count + " objects with indexed field"); Open(ConfigureIndexTest()); Store(); UpdateItems(objectsToUpdate); Close(); } // end RunIndexTest private void Init() { _count = 1000; _depth = 90; _isClientServer = false; } // end Init private void InitDifferentObjectsTest() { _count = 1000; _depth = 1; _isClientServer = false; } // end InitDifferentObjectsTest private void InitForClientServer() { _count = 1000; _depth = 90; _isClientServer = true; _host = "localhost"; } // end InitForClientServer private void InitForRamDriveTest() { _count = 30000; _depth = 1; _filePath = "r:\\performance.db4o"; _isClientServer = false; } // end InitForRamDriveTest private void InitForHardDriveTest() { _count = 10000; _depth = 3; _filePath = "performance.db4o"; _isClientServer = false; } // end InitForHardDriveTest private void InitForCommitTest() { _count = 10000; _commitInterval = 1000; _depth = 3; _isClientServer = false; } // end InitForCommitTest private void Clean() { File.Delete(_filePath); } // end Clean private IConfiguration Configure() { IConfiguration config = Db4oFactory.NewConfiguration(); // using MemoryIoAdapter improves the performance // by replacing the costly disk IO operations with // memory access config.Io(new MemoryIoAdapter()); return config; } // end Configure private IConfiguration ConfigureTP() { IConfiguration config = Db4oFactory.NewConfiguration(); // With Transparent Persistence enabled only modified // objects are written to disk. This allows to achieve // better performance config.ObjectClass(typeof(Item)).CascadeOnUpdate(true); return config; } // end ConfigureTP private IConfiguration ConfigureCascade() { IConfiguration config = Db4oFactory.NewConfiguration(); // CascadeOnUpdate can be a performance-killer for // deep object hierarchies config.ObjectClass(typeof(Item)).CascadeOnUpdate(true); return config; } // end ConfigureCascade private IConfiguration ConfigureIndexTest() { IConfiguration config = Db4oFactory.NewConfiguration(); config.Io(new MemoryIoAdapter()); config.ObjectClass(typeof(Item)).ObjectField("_name").Indexed(true); return config; } // end ConfigureIndexTest private IConfiguration ConfigureForCommitTest() { IConfiguration config = Db4oFactory.NewConfiguration(); // the Commit information is physically written // and in the correct order config.FlushFileBuffers(true); return config; } // end ConfigureForCommitTest private IConfiguration ConfigureClientServer() { IConfiguration config = Db4oFactory.NewConfiguration(); config.ClientServer().SingleThreadedClient(true); return config; } // end ConfigureClientServer private IConfiguration ConfigureDriveTest() { IConfiguration config = Db4oFactory.NewConfiguration(); config.FlushFileBuffers(true); return config; } // end ConfigureDriveTest private void Store() { StartTimer(); for (int i = 0; i < _count; i++) { Item item = new Item("level" + i, null); for (int j = 1; j < _depth; j++) { item = new Item("level" + i + "/" + j, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end Store private void StoreActivatableItems() { StartTimer(); for (int i = 0; i < _count; i++) { ActivatableItem item = new ActivatableItem("level" + i, null); for (int j = 1; j < _depth; j++) { item = new ActivatableItem("level" + i + "/" + j, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreActivatableItems private void StoreInherited() { StartTimer(); for (int i = 0; i < _count; i++) { ItemDerived item = new ItemDerived("level" + i, null); for (int j = 1; j < _depth; j++) { item = new ItemDerived("level" + i + "/" + j, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreInherited private void StoreWithStringBuilder() { StartTimer(); for (int i = 0; i < _count; i++) { ItemWithStringBuilder item = new ItemWithStringBuilder(new StringBuilder("level" + i), null); for (int j = 1; j < _depth; j++) { item = new ItemWithStringBuilder(new StringBuilder("level" + i + "/" + j), item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreWithStringBuilder private void StoreSimplest() { StartTimer(); for (int i = 0; i < _count; i++) { SimplestItem item = new SimplestItem(i, null); for (int j = 1; j < _depth; j++) { item = new SimplestItem(i, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreSimplest private void StoreWithArray() { StartTimer(); int[] array = new int[] { 1, 2, 3, 4 }; for (int i = 0; i < _count; i++) { int[] id = new int[] { 1, 2, 3, 4 }; ItemWithArray item = new ItemWithArray(id, null); for (int j = 1; j < _depth; j++) { int[] id1 = new int[] { 1, 2, 3, 4 }; item = new ItemWithArray(id1, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreWithArray private void StoreWithArrayList() { StartTimer(); ArrayList idList = new ArrayList(); idList.Add(1); idList.Add(2); idList.Add(3); idList.Add(4); for (int i = 0; i < _count; i++) { ArrayList ids = new ArrayList(); ids.AddRange(idList); ItemWithArrayList item = new ItemWithArrayList(ids, null); for (int j = 1; j < _depth; j++) { ArrayList ids1 = new ArrayList(); ids1.AddRange(idList); item = new ItemWithArrayList(ids1, item); } objectContainer.Store(item); } objectContainer.Commit(); StopTimer("Store " + TotalObjects() + " objects"); } // end StoreWithArrayList private int TotalObjects() { return _count * _depth; } // end TotalObjects private void Open(IConfiguration config) { if (_isClientServer) { int port = TCP ? PORT : 0; string user = "db4o"; string password = user; objectServer = Db4oFactory.OpenServer(_filePath, port); objectServer.GrantAccess(user, password); objectContainer = TCP ? Db4oFactory.OpenClient(_host, port, user, password) : objectServer.OpenClient(); } else { objectContainer = Db4oFactory.OpenFile(config, _filePath); } } // end Open private void Close() { objectContainer.Close(); if (_isClientServer) { objectServer.Close(); } } //end Close private void StartTimer() { _startTime = DateTime.Now.Ticks; } // end StartTimer private void StopTimer(string message) { long stop = DateTime.Now.Ticks; long duration = stop - _startTime; System.Console.WriteLine(message + ": " + duration + " ticks"); } // end StopTimer public class Item { public string _name; public Item _child; public Item() { } public Item(string name, Item child) { _name = name; _child = child; } }
More Reading: