I have been investigating query timings to assess indexing strategies, and have noticed that the query engine seems to be filtering on fields from the WHERE
clause that were already used in the index scan. This seemingly-redundant filtering is not insignificant and can a significant percentage of total execution time, increasing proportionally with the number of results in the Filter input set.
In a contrived test I created an array index:
CREATE INDEX idx_array_test ON web_api(DISTINCT things);
I then inserted 375 documents, and ran the following query:
SELECT META().id, things
FROM web_api
WHERE ANY x in things SATISFIES x=27 END;
This query averages around 12ms with 242 results, and the execution plan shows 13-40% (typically 20%) of time spent in the Filter
operator.
Why is this happening? Does the query optimiser not realise this filtering is redundant?
This was measured with Couchbase Enterprise 5.1.1 build 5723 obtained from Docker hub, Couchbase bucket type with 1GB memory quota, single node cluster and full ejection method.
Sample plan text is below:
{
"#operator": "Sequence",
"#stats": {
"#phaseSwitches": 2,
"execTime": "651ns",
"kernTime": "11.365961ms"
},
"~children": [
{
"#operator": "Authorize",
"#stats": {
"#phaseSwitches": 4,
"execTime": "1.393µs",
"kernTime": "10.558929ms",
"servTime": "789.872µs"
},
"privileges": {
"List": [
{
"Target": "default:web_api",
"Priv": 7
}
]
},
"~child": {
"#operator": "Sequence",
"#stats": {
"#phaseSwitches": 3,
"execTime": "2.07µs",
"kernTime": "10.552456ms"
},
"~children": [
{
"#operator": "DistinctScan",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 971,
"execTime": "139.101µs",
"kernTime": "62.691µs",
"servTime": "1.113646ms"
},
"scan": {
"#operator": "IndexScan2",
"#stats": {
"#itemsOut": 242,
"#phaseSwitches": 973,
"execTime": "277.512µs",
"kernTime": "86.599µs",
"servTime": "790.283µs"
},
"index": "idx_array_test",
"index_id": "2f231e73ac47026a",
"index_projection": {
"primary_key": true
},
"keyspace": "web_api",
"namespace": "default",
"spans": [
{
"exact": true,
"range": [
{
"high": "27",
"inclusion": 3,
"low": "27"
}
]
}
],
"using": "gsi",
"#time_normal": "00:00.0010",
"#time_absolute": 0.001067795
},
"#time_normal": "00:00.0012",
"#time_absolute": 0.0012527469999999998
},
{
"#operator": "Fetch",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 977,
"execTime": "488.294µs",
"kernTime": "1.036971ms",
"servTime": "4.517499ms"
},
"keyspace": "web_api",
"namespace": "default",
"#time_normal": "00:00.0050",
"#time_absolute": 0.005005793000000001
},
{
"#operator": "Sequence",
"#stats": {
"#phaseSwitches": 5,
"execTime": "1.703µs",
"kernTime": "10.539188ms"
},
"~children": [
{
"#operator": "Filter",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 973,
"execTime": "2.635735ms",
"kernTime": "6.112176ms"
},
"condition": "any `x` in (`web_api`.`things`) satisfies (`x` = 27) end",
"#time_normal": "00:00.0026",
"#time_absolute": 0.0026357349999999997
},
{
"#operator": "InitialProject",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 973,
"execTime": "1.011397ms",
"kernTime": "7.782108ms"
},
"result_terms": [
{
"expr": "(meta(`web_api`).`id`)"
},
{
"expr": "(`web_api`.`things`)"
}
],
"#time_normal": "00:00.0010",
"#time_absolute": 0.001011397
},
{
"#operator": "FinalProject",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 975,
"execTime": "142.634µs",
"kernTime": "10.387341ms"
},
"#time_normal": "00:00.0001",
"#time_absolute": 0.000142634
}
],
"#time_normal": "00:00.0000",
"#time_absolute": 0.000001703
}
],
"#time_normal": "00:00.0000",
"#time_absolute": 0.0000020699999999999997
},
"#time_normal": "00:00.0007",
"#time_absolute": 0.000791265
},
{
"#operator": "Stream",
"#stats": {
"#itemsIn": 242,
"#itemsOut": 242,
"#phaseSwitches": 491,
"execTime": "19.976µs",
"kernTime": "11.340177ms"
},
"#time_normal": "00:00.0000",
"#time_absolute": 0.000019976
}
],
"~versions": [
"2.0.0-N1QL",
"5.1.1-5723-enterprise"
],
"#time_normal": "00:00",
"#time_absolute": 0
}