Wiki source code of Performances development best practices
Version 1.21 by Thomas Mortagne on 2025/05/16
Hide last authors
author | version | line-number | content |
---|---|---|---|
![]() |
1.1 | 1 | {{box cssClass="floatinginfobox" title="**Contents**"}}{{toc/}}{{/box}} |
2 | |||
3 | = Database | ||
4 | |||
5 | == Index | ||
6 | |||
7 | Filtering and ordering on a non indexed field (for example, searching something in the content of a document) will cause very important performance problems as soon as that tables starts to contains a lot of entries. | ||
8 | |||
9 | You can also have similar problem when combining several indexed field in the same ##WHERE## clause as in theory, for this to be fast you would need to have a index combining those fields. Unfirtunately, very often, it's not possible in XWiki to do that (at least with MySQL) because most String field already have the maximum size accepted for an index and combining them would go beyond that limit. | ||
10 | |||
11 | The alternatives are generally: | ||
12 | * use the Solr ##search## core instead | ||
13 | * do post filtering/ordering on Java side (but this is causing problem when you need pagination) | ||
14 | |||
15 | = Components | ||
16 | |||
![]() |
1.18 | 17 | == [[Wiki components>>extensions:Extension.WikiComponent Module]] are slow |
![]() |
1.1 | 18 | |
19 | Wiki component are discouraged because they are much slower than the alternatives (beside various other problems). | ||
20 | |||
![]() |
1.2 | 21 | If you really need to implement your component in a wiki page, you should take a look at [[extensions:Extension.Script Component]] (which also makes implementing, and especially registering, components in a wiki page a lot easier). What will be produced in the end is technically exactly the same thing as what you get with a component implemented in Java. |
![]() |
1.1 | 22 | |
23 | = Rendering | ||
24 | |||
![]() |
1.18 | 25 | == When [[implementing a macro>>xwiki:Documentation.DevGuide.Tutorials.WritingMacros]] |
![]() |
1.1 | 26 | |
27 | When you implement your own macro, there are various performance related things that you should be aware of. | ||
28 | |||
![]() |
1.18 | 29 | === [[Wiki macros>>xwiki:Documentation.DevGuide.Tutorials.WritingMacros.WikiMacroTutorial]] are much slower than [[Java macros>>rendering:Main.ExtendingMacro]] |
![]() |
1.1 | 30 | |
![]() |
1.7 | 31 | So you should try as much as possible to implemented Java macro (it's also much easier to write automated tests for Java macro). It's not always very practical to write complex UI in Java, but you can easily execute a [[template>>extensions:Extension.Template Module]] from your Java macro. |
![]() |
1.1 | 32 | |
![]() |
1.2 | 33 | Like with for any other component, you can implement a Java macro through [[extensions:Extension.Script Component]] if you absolutely need your macro to be implemented in a wiki page. What will be produced in the end is technically exactly the same thing as what you get with a macro implemented in Java. |
![]() |
1.1 | 34 | |
![]() |
1.7 | 35 | === Macro preparation |
![]() |
1.1 | 36 | |
37 | {{info}} | ||
38 | Currently not supported in Wiki macros. | ||
39 | {{/info}} | ||
40 | |||
41 | There are two steps in the execution of a macro: | ||
42 | * the preparation | ||
43 | * the actual execution | ||
44 | |||
45 | During the preparation step you get a chance to do everything which does not rely on any contextual information and store the result in the ##MacroBlock## (as attribute). It can improve execution time greatly because the ##MacroBlock## is generally part of a cached content, so the preparation will be executed only once for potentially many execution. | ||
46 | |||
![]() |
1.3 | 47 | === Isolated execution |
48 | |||
49 | {{version since="17.3.0"}} | ||
50 | If you macro does not modify the XDOM around it (which is the case most of the time), it's highly recommended to indicate it: | ||
51 | |||
![]() |
1.19 | 52 | * [[for java macros>>rendering:Main.ExtendingMacro]] |
53 | * [[for wiki macros>>xwiki:Documentation.DevGuide.Tutorials.WritingMacros.WikiMacroTutorial]] | ||
![]() |
1.3 | 54 | {{/version}} |
55 | |||
![]() |
1.1 | 56 | == HTML Macro |
57 | |||
![]() |
1.6 | 58 | The cleaning part of the HTML macro can be expensive, so using {{code}}clean="false"{{/code}} could have a significant impact on the performance if a lot of them are used. |
![]() |
1.7 | 59 | |
60 | == Preparation | ||
61 | |||
62 | === Preparing ##Block##s | ||
63 | |||
![]() |
1.10 | 64 | Similarly to [[what is explained for macros>>||anchor="HMacropreparation"]], it's a good idea to parse and "prepare" any wiki content you are planning to execute several times. It will generally considerably reduce the execution time. |
![]() |
1.7 | 65 | |
66 | You can do that by calling ##Transformation#prepare(Block block)## in Java. If you don't know which Transformation to apply, apply at least the ##macro## one: | ||
67 | |||
68 | {{code language="java"}} | ||
69 | @Inject | ||
70 | @Named("macro") | ||
71 | private Translation macroTransformation; | ||
72 | |||
![]() |
1.10 | 73 | private XDOM cachedXDOM; |
![]() |
1.7 | 74 | |
![]() |
1.10 | 75 | void cacheContent(String wikiContent) |
![]() |
1.7 | 76 | { |
![]() |
1.10 | 77 | this.cachedXDOM = parse(wikiContent); |
78 | this.macroTransformation.prepare(cachedBlock); | ||
![]() |
1.7 | 79 | } |
80 | |||
81 | ... | ||
82 | {{/code}} | ||
83 | |||
![]() |
1.13 | 84 | === Compiling Velocity |
![]() |
1.7 | 85 | |
![]() |
1.13 | 86 | If you have the possibility to cache a Velocity script, it's generally a good idea to pre-compile it. In the case of Velocity it means parsing the String into an AST, which can be an expensive step. |
![]() |
1.7 | 87 | |
![]() |
1.10 | 88 | {{code language="java"}} |
89 | @Inject | ||
90 | private VelocityManager velocityManager; | ||
91 | |||
92 | private VelocityTemplate cachedVelocity; | ||
93 | |||
94 | void cacheContent(String velocityScript) | ||
95 | { | ||
96 | this.cachedVelocity = this.velocityManager.compile(nameAssociatedtoTheScript, velocityScript) | ||
97 | } | ||
98 | |||
![]() |
1.12 | 99 | void evaludate(Writer writer) |
![]() |
1.10 | 100 | { |
101 | ... | ||
102 | this.velocityManager.getVelocityEngine().evaluate(velocityContext, writer, namespace, this.cachedVelocity); | ||
103 | } | ||
![]() |
1.11 | 104 | |
![]() |
1.10 | 105 | ... |
106 | {{/code}} | ||
107 | |||
![]() |
1.16 | 108 | This is, for example, what the [[##~{{velocity}}## macro>>extensions:Extension.Velocity Macro]] is doing as part of it's [[macro preparation step>>||anchor="#HMacropreparation"]]. |
![]() |
1.13 | 109 | |
![]() |
1.20 | 110 | = [[UI extensions>>extensions:Extension.UIExtension Module]] |
![]() |
1.7 | 111 | |
112 | == Wiki based UI extensions are slower than Java based ones | ||
113 | |||
114 | What is true for generic wiki components an wiki macros is true too for UI extensions. |