Speedup saving of document with a lot of xobjects
Last modified by Thomas Mortagne on 2024/11/19 16:15
Description
Saving a document which contains a lot of xobject can be very slow.
There are actually two main areas:
- slow history update (by far the main problem): XWIKI-22613
- slow actual save: XWIKI-2874
To reproduce
{{groovy}}
if ('true'.equals(request.confirm)) {
// Create a small document to gather a reference time
def smallDocument = xwiki.getDocument('Test.DocumentSave.SmallDocument')
def before = System.currentTimeMillis();
smallDocument.save("Empty save")
def after = System.currentTimeMillis();
def totalDuration = after - before;
println "Saving the empty document took **${totalDuration}ms**"
// Create the big document if it does not exist yet
def testDocument = xwiki.getDocument('Test.DocumentSave.BigDocument')
if (testDocument.isNew()) {
def testClass = testDocument.getxWikiClass().getXWikiClass()
testClass.addTextField("property", "Tests Property", 30)
for (int i = 0; i < 10000; i++) {
def testObject = testDocument.newObject('Test.DocumentSave.BigDocument')
testObject.set('property', "value${i}")
}
before = System.currentTimeMillis();
testDocument.save("Initial setup")
after = System.currentTimeMillis();
totalDuration = after - before;
println "Creating the the big document with 10000 xobjects took **${totalDuration}ms**"
}
// Re-save the document with a new xobject
testDocument = xwiki.getDocument('Test.DocumentSave.BigDocument')
def testObject = testDocument.newObject('Test.DocumentSave.BigDocument')
testObject.set('property', "extra")
before = System.currentTimeMillis();
testDocument.save("Add xobject")
after = System.currentTimeMillis();
totalDuration = after - before;
println "Saving the big document with a new xobject took **${totalDuration}ms**"
} else {
print '[[confirm>>?confirm=true]]'
}
{{/groovy}}Result
Also added some more detail on what exactly happen in each step of the script.
Create empty document: 104ms
- Before save: 0ms
- Updating the document archive: 3ms
- Creating the patch: 2ms
- Full serialization: 2ms
- Creating the patch: 2ms
- XWikiDocument save: 0ms
- Xobjects save: 0ms
- Updating the space table: 0ms
- Applying the transaction: 30ms
- Updating the document archive: 3ms
- After save: 70ms
Resave empty document: 107ms
- Before save: 0ms
- Updating the document archive: 1ms
- XWikiDocument save: 0ms
- Xobjects save: 0ms
- Updating the space table: 1ms
- Applying the transaction: 27ms
- After save: 77ms
Create big (10000 objects) document: 8387ms 
- Before save: 0ms
- Updating the document archive: 115ms
- Creating the patch: 113ms
- Full serialization: 113ms
- Creating the patch: 113ms
- XWikiDocument save: 0ms
- Xobjects save: 1911ms

- Updating the space table: 0ms
- Applying the transaction: 3424ms

- Updating the document archive: 115ms
- After save: 2931ms

Add xobject to big document: 260920ms 

- Before save: 0ms
- Updating the document archive: 253328ms
- Creating the patch: 253326ms
- Full serialization: 87ms
- Diff: 253229ms

- Creating the patch: 253326ms
- XWikiDocument save: 1ms
- Xobjects save: 1939ms

- Updating the space table: 0ms
- Applying the transaction: 2921ms

- Updating the document archive: 253328ms
- After save: 2722ms

Thomas Mortagne
Michael Hamann