Last modified by Michael Hamann on 2025/05/23

Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
4
5 = Database =
6
7 == Index ==
8
9 Filtering and ordering on a non indexed field (for example, searching for something in the content of a document) will cause very important performance problems as soon as that table starts to contain a lot of entries. Not only for the query you are trying to execute but also for other queries running in the database server.
10
11 You can also have a similar problems when combining several indexed fields in the same ##WHERE## clause, as, in theory, for this to be fast, you would need to have an index combining those fields. Unfortunately, very often, it's not possible in XWiki to do that (at least with MySQL/MariaDB) because most String columns already have the maximum size accepted for an index, and combining them would make such an index go beyond that limit.
12
13 The possible alternatives are generally:
14
15 * Use the Solr ##search## core instead.
16 * Do post filtering/ordering on your side (Java, script) instead of the database (but this can cause prove challenging when you need pagination)
17
18 = Solr =
19
20 == Commit is slow ==
21
22 Each commit to Solr can be expensive and reducing the number of commits you are doing when you send a lot of data to Solr generally have a very big speed impact.
23
24 == Use sensible limits in queries ==
25
26 Even when you want to have all results for a query (without pagination), never put a limit larger than 10k (and ideally, not larger than 1k). Instead, use cursor-based pagination to paginate through the results to obtain all matches. The reason for this is that Solr allocates arrays that are large enough to store all results that could match. While Solr automatically limits this to the number of indexed documents, when the Solr core has 30 million documents, these are around 700MB – just to answer a single query and even when this query doesn't match any documents. This makes queries slow and leads to out of memory situations.
27
28 = Components =
29
30 == [[Wiki components>>extensions:Extension.WikiComponent Module]] are slow ==
31
32 Wiki components are discouraged because they are much slower than the alternatives (beside various other problems).
33
34 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.
35
36 = Rendering =
37
38 == When [[implementing a macro>>xwiki:Documentation.DevGuide.Tutorials.WritingMacros]] ==
39
40 When you implement your own macro, there are various performance related things that you should be aware of.
41
42 === [[Wiki macros>>xwiki:Documentation.DevGuide.Tutorials.WritingMacros.WikiMacroTutorial]] are much slower than [[Java macros>>rendering:Main.ExtendingMacro]] ===
43
44 So you should try as much as possible to implement Java macros (it's also much easier to write automated tests for Java macros). 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 code.
45
46 Like with any other component, you can implement a Java macro through a [[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 (so it always have the same features).
47
48 === Macro preparation ===
49
50 {{info}}
51 Currently, not supported in Wiki macros.
52 {{/info}}
53
54 There are two steps in the execution of a macro:
55
56 * the preparation
57 * the actual execution
58
59 During the preparation step, you get a chance to do everything that does not rely on any contextual information and store the result in the ##MacroBlock## (as attribute). For example message macro, like the info macro, parse and prepare the passed content. It can improve execution time greatly because the ##MacroBlock## is generally part of cached data, so the preparation will be executed only once for potentially many executions.
60
61 === Isolated execution ===
62
63 {{version since="17.3.0"}}
64 If your macro does not modify the XDOM around it (which is the case most of the time), it's highly recommended to indicate it:
65
66 * For Java macros: see [[rendering:Main.ExtendingMacro]]
67 * For wiki macros: see [[xwiki:Documentation.DevGuide.Tutorials.WritingMacros.WikiMacroTutorial]]
68 {{/version}}
69
70 This will help speed up the macro transformation ordering of macros by reducing a lot the navigation it needs to do in the blocks.
71
72 == HTML Macro ==
73
74 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.
75
76 == Preparation ==
77
78 === Preparing ##Block##s ===
79
80 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.
81
82 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:
83
84 {{code language="java"}}
85 @Inject
86 @Named("macro")
87 private Translation macroTransformation;
88
89 private XDOM cachedXDOM;
90
91 void cacheContent(String wikiContent)
92 {
93 this.cachedXDOM = parse(wikiContent);
94 this.macroTransformation.prepare(cachedBlock);
95 }
96
97 ...
98 {{/code}}
99
100 === Compiling Velocity ===
101
102 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.
103
104 {{code language="java"}}
105 @Inject
106 private VelocityManager velocityManager;
107
108 private VelocityTemplate cachedVelocity;
109
110 void cacheContent(String velocityScript)
111 {
112 this.cachedVelocity = this.velocityManager.compile(nameAssociatedtoTheScript, velocityScript)
113 }
114
115 void evaluate(Writer writer)
116 {
117 ...
118 this.velocityManager.getVelocityEngine().evaluate(velocityContext, writer, namespace, this.cachedVelocity);
119 }
120
121 ...
122 {{/code}}
123
124 This is, for example, what the [[##~~{~~{velocity}}## macro>>extensions:Extension.Velocity Macro]] is doing as part of its [[macro preparation step>>||anchor="#HMacropreparation"]].
125
126 = [[UI extensions>>extensions:Extension.UIExtension Module]] =
127
128 == Wiki-based UI extensions are slower than Java-based ones ==
129
130 What is true for generic wiki components and wiki macros is also true for UI extensions. Since UI extension are components, you can perfectly implement them in Java:
131
132 {{code language="java"}}
133 @Component
134 @Named(MyUserProfileUIExtension.ID)
135 @Singleton
136 public class MyUserProfileUIExtension implements UIExtension, Initializable
137 {
138 /**
139 * The id of the UI extension.
140 */
141 public static final String ID = "my.user.profile.uiextension";
142
143 @Inject
144 private TemplateManager templates;
145
146 private Map<String, String> parameters;
147
148 @Override
149 public void initialize() throws InitializationException
150 {
151 this.parameters = new HashMap<>();
152 this.parameters.put("id", "myuserprofileuiextension");
153 this.parameters.put("icon", "key");
154 }
155
156 @Override
157 public String getId()
158 {
159 return ID;
160 }
161
162 @Override
163 public String getExtensionPointId()
164 {
165 return "org.xwiki.plaftorm.user.profile.menu";
166 }
167
168 @Override
169 public Map<String, String> getParameters()
170 {
171 return this.parameters;
172 }
173
174 @Override
175 public Block execute()
176 {
177 // The actual UI is written in a template file located in the JAR
178 return this.templates.executeNoException("my/userprofile/uiextension.vm");
179 }
180 }
181 {{/code}}
182
183 Of course, this kind of UI extension is also less fragile (since it's easy to break a wiki page by mistake).

Get Connected