Trying to used named parameters in a N1QL query and that seems to work fine for equals values, however, our query has IN and a List is provided, the query plan changes and performance is awful.
our query:
SELECT count(1) FROM `bucket` WHERE `user` is not null" +
" AND `user`.`type` = $accountType" +
" AND `user`.`id` = $accountId" +
" AND split(meta().id, '::')[0] in ["e1", "e2", "e3", "e4"];
or (with replacement for IN)
SELECT count(1) FROM `bucket` WHERE `user` is not null" +
" AND `user`.`type` = $accountType" +
" AND `user`.`id` = $accountId" +
" AND split(meta().id, '::')[0] in $environments";
Setting up the $accountType and $accountId work just fine, but $environments is a List of String. When that comes into play, the query plan changes and performance is very bad (timeout when using a direct string instead works in 100ms).
The String based query plan is like this:
{
"plan":
{
"~children": [
{
"scan":
{
"keyspace": "bucket",
"spans": [
{
"Range":
{
"High": ["\"e1\"", "$accountType", "successor($accountId)"],
"Low": ["\"e1\"", "$accountType", "$accountId"],
"Inclusion": 1
}
},
{
"Range":
{
"High": ["\"e2\"", "$accountType", "successor($accountId)"],
"Low": ["\"e2\"", "$accountType", "$accountId"],
"Inclusion": 1
}
},
{
"Range":
{
"High": ["\"e3\"", "$accountType", "successor($accountId)"],
"Low": ["\"e3\"", "$accountType", "$accountId"],
"Inclusion": 1
}
},
{
"Range":
{
"High": ["\"e4\"", "$accountType", "successor($accountId)"],
"Low": ["\"e4\"", "$accountType", "$accountId"],
"Inclusion": 1
}
}],
"#operator": "IndexScan",
"using": "gsi",
"namespace": "default",
"index": "user_idx",
"index_id": "619388af1e312812",
"covers": ["cover ((split((meta(`bucket`).`id`), \"::\")[0]))", "cover (((`bucket`.`user`).`type`))", "cover (((`bucket`.`user`).`id`))", "cover (((`bucket`.`user`).`ttlInSec`))", "cover ((meta(`bucket`).`id`))"],
"filter_covers":
{
"cover (((`bucket`.`user`) is not null))": true
}
},
"#operator": "DistinctScan"
},
{
"~child":
{
"~children": [
{
"#operator": "Filter",
"condition": "(((cover (((`bucket`.`user`) is not null)) and (cover (((`bucket`.`user`).`type`)) = $accountType)) and (cover (((`bucket`.`user`).`id`)) = $accountId)) and (cover ((split((meta(`bucket`).`id`), \"::\")[0])) in [\"e1\", \"e2\", \"e3\", \"e4\"]))"
},
{
"group_keys": [],
"#operator": "InitialGroup",
"aggregates": ["count(1)"]
}],
"#operator": "Sequence"
},
"#operator": "Parallel"
},
{
"group_keys": [],
"#operator": "IntermediateGroup",
"aggregates": ["count(1)"]
},
{
"group_keys": [],
"#operator": "FinalGroup",
"aggregates": ["count(1)"]
},
{
"~child":
{
"~children": [
{
"#operator": "InitialProject",
"result_terms": [
{
"as": "count",
"expr": "count(1)"
}]
},
{
"#operator": "FinalProject"
}],
"#operator": "Sequence"
},
"#operator": "Parallel"
}],
"#operator": "Sequence"
},
"text": "SELECT count(1) as count FROM `bucket` WHERE `user` is not null AND `user`.`type` = $accountType AND `user`.`id` = $accountId AND split(meta().id, '::')[0] in ['e1','e2','e3','e4']"
}
and the named parameter based list returns:
{
"plan":
{
"~children": [
{
"keyspace": "bucket",
"spans": [
{
"Range":
{
"Low": ["null", "$accountType", "$accountId"],
"Inclusion": 0
}
}],
"#operator": "IndexScan",
"using": "gsi",
"namespace": "default",
"index": "user_idx",
"index_id": "619388af1e312812",
"covers": ["cover ((split((meta(`bucket`).`id`), \"::\")[0]))", "cover (((`bucket`.`user`).`type`))", "cover (((`bucket`.`user`).`id`))", "cover (((`bucket`.`user`).`ttlInSec`))", "cover ((meta(`bucket`).`id`))"],
"filter_covers":
{
"cover (((`bucket`.`user`) is not null))": true
}
},
{
"~child":
{
"~children": [
{
"#operator": "Filter",
"condition": "(((cover (((`bucket`.`user`) is not null)) and (cover (((`bucket`.`user`).`type`)) = $accountType)) and (cover (((`bucket`.`user`).`id`)) = $accountId)) and (cover ((split((meta(`bucket`).`id`), \"::\")[0])) in $environments))"
},
{
"group_keys": [],
"#operator": "InitialGroup",
"aggregates": ["count(1)"]
}],
"#operator": "Sequence"
},
"#operator": "Parallel"
},
{
"group_keys": [],
"#operator": "IntermediateGroup",
"aggregates": ["count(1)"]
},
{
"group_keys": [],
"#operator": "FinalGroup",
"aggregates": ["count(1)"]
},
{
"~child":
{
"~children": [
{
"#operator": "InitialProject",
"result_terms": [
{
"as": "count",
"expr": "count(1)"
}]
},
{
"#operator": "FinalProject"
}],
"#operator": "Sequence"
},
"#operator": "Parallel"
}],
"#operator": "Sequence"
},
"text": "SELECT count(1) as count FROM `bucket` WHERE `user` is not null AND `user`.`type` = $accountType AND `user`.`id` = $accountId AND split(meta().id, '::')[0] in $environments"
}