You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/language/learn-ql/writing-queries/debugging-queries.rst
+11-16Lines changed: 11 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
Query writing: common performance issues
2
2
========================================
3
3
4
-
This topic offers some simple tips on how to avoid commons problems that can affect the performance of your queries.
4
+
This topic offers some simple tips on how to avoid common problems that can affect the performance of your queries.
5
5
Before reading the tips below, it is worth reiterating a few important points about CodeQL and the QL language:
6
6
7
7
- CodeQL `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ are evaluated to database `tables <https://en.wikipedia.org/wiki/Table_(database)>`__. Large predicates generate large tables with many rows, and are therefore expensive to compute.
@@ -22,13 +22,18 @@ This leads to computing the `Cartesian product <https://en.wikipedia.org/wiki/Ca
22
22
23
23
This can occur whenever you inadvertently fail to specify restrictions on your variables.
24
24
25
-
For instance, in the following case none of the parameters are related in the example predicate ``methodAndAClass``, and therefore the results are unrestricted::
25
+
For instance, consider the following predicate that checks whether a Java method ``m`` may access a field ``f``::
26
26
27
-
// BAD! Cross-product
28
-
predicate methodAndAClass(Method m, Class c) {
29
-
any()
27
+
predicate mayAccess(Method m, Field f) {
28
+
f.getAnAccess().getEnclosingCallable() = m
29
+
or
30
+
not exists(m.getBody())
30
31
}
31
32
33
+
The predicate holds if ``m`` contains an access to ``f``, but also conservatively assumes that methods without bodies (for example, native methods) may access *any* field.
34
+
35
+
However, if ``m`` is a native method, the table computed by ``mayAccess`` will contain a row ``m, f`` for *all* fields ``f`` in the codebase, which could potentially be very large.
36
+
32
37
This example shows a similar mistake in a member predicate::
33
38
34
39
class Foo extends Class {
@@ -40,19 +45,9 @@ This example shows a similar mistake in a member predicate::
40
45
...
41
46
}
42
47
43
-
Note that while `getToString()` does not declare any parameters, it has two implicit parameters `result` and `this`, which it fails to relate. Hence the table computed by `getToString()` contains a row for every combination of values of `result` and `this`, that is, for every combination of a method named `"ToString"` and an instance of `Foo`.
48
+
Note that while ``getToString()`` does not declare any parameters, it has two implicit parameters, ``result`` and ``this``, which it fails to relate. Therefore, the table computed by ``getToString()`` contains a row for every combination of ``result`` and ``this``. That is, a row for every combination of a method named ``"ToString"`` that is an instance of ``Foo``.
44
49
To avoid making this mistake, ``this`` should be restricted in the member predicate ``getToString()`` on the class ``Foo``.
45
50
46
-
Finally, consider a predicate of the following form::
47
-
48
-
predicate p(T1 x1, T2 x2) {
49
-
<disjunction 1> or
50
-
<disjunction 2> or
51
-
...
52
-
}
53
-
54
-
In this situation, if ``x1`` and ``x2`` are not mentioned in all ``<disjunction i>`` terms, the compiler will produce the Cartesian product between what you wanted and all possible values of the unused parameter.
0 commit comments