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.
Example15.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;