15.8.3. Pre-compilation of XPath and XQuery Expressions
Virtuoso compiles XPath and XQuery expressions as early as it is possible.
E.g. if the first argument of xquery_eval()
is a string constant then the SQL compiler will invoke the XQuery compiler to avoid
on-demand compilation(s) of this text.
This feature significantly enhances performance of XQuery expressions embedded in SQL.
For a simple search on XML document of average size
the compilation time can be three times greater than execution time.
In addition, the use of sql:column()
special XQuery function is possible only when pre-compilation can be done by SQL compiler.
Pre-compilation is impossible if the text of the expression is not a constant. The typical case is passing an XQuery expression as parameter to a function. In this case the expression is compiled during the call of xquery_eval() and stored for future use. If the same string is passed again to the same invocation of xquery_eval() then a stored compiled expression is used.
Only partial pre-compilation is possible if XQuery expression refers to
not-yet defined extension functions or to external resources.
Partial pre-compilation gives little gain in speed, but it allows
the use of
sql:column()
The most important fact about pre-compilation is that passing parameters into XQuery statement is much more efficient than printing then into the text of the query. This is similar to SQL queries.
Example 15.22. Good and Poor Coding Practices
GOOD The expression is compiled once when SQL query is compiled:
select xquery_eval('count(//abstract)', SOURCE_XML) from LIB..ARTICLES;
GOOD The expression is compiled once when SQL query is compiled:
select xquery_eval('count(//article[@id=$main_id]/abstract)', SOURCE_XML, 1, vector('main_id', MAIN_ID)) from LIB..ARTICLES;
POOR The expression is compiled once per data row. In addition, a hard-to-find error will occur if a value of MAIN_ID may contain double quote or a backslash character.
select xquery_eval(sprintf('count(//article[@id="%s"]/abstract)', MAIN_ID), SOURCE_XML) from LIB..ARTICLES;
GOOD
The XQuery expression is compiled once per execution of
the SQL query.
The SQL compiler pays special attention to queries that import external resources, because
the content and availability of these resources may differ from call to call.
In addition, importing an external resource is usually not possible during SQL compilation due to
deadlock danger, so the compilation is postponed until run time, but this is not too bad anyway.
Even in this sophisticated case, XQuery can contain calls of
sql:column()
.
select xquery_eval(' namespace tools="http://www.example.com/lib/tools/" import define "http://www.example.com/lib/tools/common.xqr" tools:extract-keywords(//abstract)', SOURCE_XML) from LIB..ARTICLES;
GOOD Two XQuery expressions are compiled during SQL compilation.
select case when SOURCE_IS_DOCBOOK then xquery_eval ('//formalpara[title="See Also"]/para', SOURCE_XML) else xquery_eval ('//p[@style="seealso"]', SOURCE_XML) end from LIB..ARTICLES;
POOR Virtuoso can not pre-compile XQquery expressions. Moreover, only one precompiled expression is cached per occurrence of xquery_eval() in the SQL statement so it is possible that an XQuery compiler will start once per data row.
select xquery_eval ( case when SOURCE_IS_DOCBOOK then '//formalpara[title="See Also"]/para' else '//p[@style="seealso"]' end, SOURCE_XML) from LIB..ARTICLES;