EXPLAIN FUNCTION
- reference
Use EXPLAIN FUNCTION to expose the execution plan for the SQL++ subqueries or embedded statements that a specified user-defined function contains.
Purpose
You can request the execution plan for an inline or external user-defined function.
-
Inline functions are defined using SQL++ expressions. For an inline function, EXPLAIN FUNCTION returns the query plans for all of the subqueries present in the function body.
-
External functions are defined using JavaScript. For an external function, EXPLAIN FUNCTION returns the query plans for all embedded SQL++ queries inside the referenced JavaScript body, or the line number on which a N1QL() call appears. Line numbers are calculated from the beginning of the JavaScript function definition.
The following constraints apply:
-
If a user-defined function itself contains other, nested user-defined function executions, EXPLAIN FUNCTION generates the query plan for the specified function only, and not for its nested SQL++ queries.
-
If an external function defines an alias for a N1QL() call, EXPLAIN FUNCTION cannot return its line number.
Prerequisites
| To execute EXPLAIN FUNCTION on … | You must have … |
|---|---|
Global inline functions |
Execute Global Functions role. |
Scoped inline functions |
Execute Scope Functions role, with permissions on the specified bucket and scope. |
Global external functions |
Execute Global External Functions role. |
Scoped external functions |
Execute Scope External Functions role, with permissions on the specified bucket and scope. |
You must also have the necessary privileges required for the SQL++ statements inside the function.
For more information about user roles, see Authorization.
Syntax
explain-function ::= 'EXPLAIN' 'FUNCTION' function
| function |
Function Name
function ::= ( namespace ':' ( bucket '.' scope '.' )? )? identifier
The name of the function.
This is usually an unqualified identifier, such as func1 or `func-1`.
In this case, the path to the function is determined by the current query context.
To get the plan for a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as default:func1.
Similarly, to get the plan for a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as default:`travel-sample`.inventory.func1.
For more information, see Global Functions and Scoped Functions.
| The name of a user-defined function is case-sensitive, unlike that of a built-in function. You must get the plan for the user-defined function using the same case that was used when it was created. |
Examples
To try the examples in this section, set the query context to the inventory scope in the travel sample dataset.
For more information, see Query Context.
In this example, you create an inline function named func1 and then request the plan for its subquery.
CREATE FUNCTION func1() {
(SELECT * FROM default:`travel-sample`.inventory.route)};
EXPLAIN FUNCTION func1;
[
{
"function": "default:travel-sample.inventory.func1",
"plans": [
{
"cardinality": 24024,
"cost": 33346.763562464446,
"plan": {
"#operator": "Sequence",
"~children": [
{
"#operator": "PrimaryScan3",
"bucket": "travel-sample",
"index": "def_inventory_route_primary",
"index_projection": {
"primary_key": true
},
"keyspace": "route",
"namespace": "default",
"optimizer_estimates": {
"cardinality": 24024,
"cost": 4108.612246388904,
"fr_cost": 12.170521655277593,
"size": 11
},
"scope": "inventory",
"using": "gsi"
},
{
"#operator": "Fetch",
"bucket": "travel-sample",
"keyspace": "route",
"namespace": "default",
"optimizer_estimates": {
"cardinality": 24024,
"cost": 32773.70177195316,
"fr_cost": 25.36320769946525,
"size": 569
},
"scope": "inventory"
},
{
"#operator": "Parallel",
"~child": {
"#operator": "Sequence",
"~children": [
{
"#operator": "InitialProject",
"discard_original": true,
"optimizer_estimates": {
"cardinality": 24024,
"cost": 33346.763562464446,
"fr_cost": 25.387061420349003,
"size": 569
},
"result_terms": [
{
"expr": "self",
"star": true
}
]
}
]
}
}
]
},
"statement": "select self.* from `default`:`travel-sample`.`inventory`.`route`"
}
]
}
]
This example assumes that you have defined a JavaScript library in the current query context named lib1.
Add a JavaScript function named function1 to that library:
function function1() {
SELECT * FROM default:`travel-sample`; (1)
N1QL("SELECT 100"); (2)
}
| 1 | An embedded SQL++ statement. |
| 2 | A N1QL() call that executes a SQL++ statement. |
Then create the corresponding SQL++ user-defined function for that JavaScript function, named jsfunction1, and request the plan information for the statements within the function definition:
CREATE FUNCTION jsfunction1()
LANGUAGE JAVASCRIPT
AS "function1" AT "lib1";
EXPLAIN FUNCTION jsfunction1;
[
{
"function": "default:travel-sample.inventory.jsfunction1",
"line_numbers": [
3 (1)
],
"plans": [ (2)
{
"cardinality": 31591,
"cost": 47086.49704894546,
"plan": {
"#operator": "Authorize",
"privileges": {
"List": [
{
"Target": "default:travel-sample",
"Priv": 7,
"Props": 0
}
]
},
"~child": {
"#operator": "Sequence",
"~children": [
{
"#operator": "Sequence",
"~children": [
{
"#operator": "PrimaryScan3",
"index": "def_primary",
"index_projection": {
"primary_key": true
},
"keyspace": "travel-sample",
"namespace": "default",
"optimizer_estimates": {
"cardinality": 31591,
"cost": 5402.279801258844,
"fr_cost": 12.170627071041082,
"size": 11
},
"using": "gsi"
},
{
"#operator": "Fetch",
"keyspace": "travel-sample",
"namespace": "default",
"optimizer_estimates": {
"cardinality": 31591,
"cost": 46269.39474997121,
"fr_cost": 25.46387878667884,
"size": 669
}
},
{
"#operator": "Parallel",
"~child": {
"#operator": "Sequence",
"~children": [
{
"#operator": "InitialProject",
"discard_original": true,
"optimizer_estimates": {
"cardinality": 31591,
"cost": 47086.49704894546,
"fr_cost": 25.489743820991595,
"size": 669
},
"preserve_order": true,
"result_terms": [
{
"expr": "self",
"star": true
}
]
}
]
}
}
]
},
{
"#operator": "Stream",
"optimizer_estimates": {
"cardinality": 31591,
"cost": 47086.49704894546,
"fr_cost": 25.489743820991595,
"size": 669
},
"serializable": true
}
]
}
},
"statement": "SELECT * FROM default:`travel-sample` ;"
}
]
}
]
| 1 | The line number in the JavaScript function that includes a N1QL() call. |
| 2 | The query plan for the embedded SQL++ statement. |
Related Links
-
For an introduction to user-defined functions, see User-Defined Functions for Queries.
-
For more information about JavaScript functions, see JavaScript Functions for Query Reference.
-
To manage JavaScript libraries, see Query Functions REST API.
-
To create user-defined functions, see CREATE FUNCTION.
-
To execute a user-defined function, see EXECUTE FUNCTION.
-
To include a user-defined function in an expression, see User-Defined Functions.
-
To monitor user-defined functions, see Monitor Functions.
-
To drop a user-defined function, see DROP FUNCTION.