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
+42Lines changed: 42 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,6 +81,48 @@ That is, you should define a *base case* that allows the predicate to *bottom ou
81
81
The query optimizer has special data structures for dealing with `transitive closures <https://help.semmle.com/QL/ql-handbook/recursion.html#transitive-closures>`__.
82
82
If possible, use a transitive closure over a simple recursive predicate, as it is likely to be computed faster.
83
83
84
+
Folding predicates
85
+
~~~~~~~~~~~~~~~~~~
86
+
87
+
Sometimes you can assist the query optimizer by "folding" parts of large predicates out into smaller predicates.
88
+
89
+
The general principle is to split off chunks of work that are:
90
+
91
+
- **linear**, so that there is not too much branching.
92
+
- **tightly bound**, so that the chunks join with each other on as many variables as possible.
93
+
94
+
95
+
In the following example, we explore some lookups on two ``Element``\ s:
Going from ``Element -> File`` and ``Element -> Location -> StartLine`` is linear--that is, there is only one ``File``, ``Location``, etc. for each ``Element``.
106
+
107
+
However, as written it is difficult for the optimizer to pick out the best ordering. Generally, we want to do the quick, linear parts first, and then join on the resultant larger tables. Joining first and then doing the linear lookups later would likely result in poor performance. We can initiate this kind of ordering by splitting the above predicate as follows:
108
+
109
+
.. code-block:: ql
110
+
111
+
predicate locInfo(Element e, string name, File f, int startLine) {
112
+
name = e.getName() and
113
+
f = e.getFile() and
114
+
startLine = e.getLocation().getStartLine()
115
+
}
116
+
117
+
predicate sameLoc(Element e1, Element e2) {
118
+
exists(string name, File f, int startLine |
119
+
locInfo(e1, name, f, startLine) and
120
+
locInfo(e2, name, f, startLine)
121
+
)
122
+
}
123
+
124
+
Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join.
0 commit comments