我在理解 couchbase 查询计划的工作方式方面存在问题。我将 SpringData 与 Couchbase 4.1 一起使用,并提供 Couchbase 存储库的自定义实现。在我的 Couchbase 存储库的自定义实现中,我有以下方法:
String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1";
JsonObject params = JsonObject.create()
.put(CLASS_VARIABLE, MyClass.class.getCanonicalName())
.put(ID_VARIABLE, segmentId);
N1qlQuery query = N1qlQuery.parameterized(queryAsString, params);
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class);
return resultList.isEmpty() ? null : resultList.get(0);
结果,Spring Data 向 Couchbase 生成以下 json 对象表示的查询:
{
"$class":"path/MyClass",
"statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1",
"id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8"
}
当我通过 Java 和 N1QL Rest Api 或通过 cbq consol 执行它时,问题在于性能。为了在 cbq 中执行此查询,我只需将参数引用替换为精确值。
在 select 语句之前添加 EXPLAIN 子句后,我提到了不同的执行计划。通过 Java Spring Data 或 N1QL Rest Api 将此查询作为参数化查询执行我已经提到该查询不使用我专门为这种情况创建的索引。索引定义如下:
CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI;
因此,当我通过 cbq consol 执行查询时,Couchbase 使用我的 idnex 并且查询性能非常好。但是,当我通过 N1QL rest api 或 Java 执行此查询时,我看到该查询不使用我的索引。您可以在下面找到证明这一事实的部分执行计划:
"~children": [
{
"#operator": "PrimaryScan",
"index": "#primary",
"keyspace": "CSM",
"namespace": "default",
"using": "gsi"
},
那么,问题在于,couchbase 查询优化器的权利和合法行为是什么?这是否意味着查询计划不考虑参数的实际值?并且我是否手动将值放入查询字符串或存在任何其他方式来使用具有正确索引选择的 N1Ql 参数化查询?
编辑
根据shashi raj的回答,我将 N1qlParams.build().adhoc(false) 参数添加到参数化的 N1QL 查询中。这并不能解决我的问题,因为我仍然有这个查询的性能问题。此外,当我打印查询时,我看到它与我之前描述的相同。因此,我的查询仍然错误分析并导致性能下降。