Couchbase 在 N1QL 参数化查询中使用了错误的索引

4th*_*eam 5 java couchbase spring-data spring-data-couchbase couchbase-java-api

我对 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);
Run Code Online (Sandbox Code Playgroud)

结果,Spring Data 生成以下 json 对象,表示对 Couchbase 的查询:

{
    "$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"
}
Run Code Online (Sandbox Code Playgroud)

当我通过 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;
Run Code Online (Sandbox Code Playgroud)

因此,当我通过 cbq consol 执行查询时,Couchbase 使用我的 idnex 并且查询性能非常好。但是,当我通过 N1QL Rest api 或 Java 执行此查询时,我发现该查询不使用我的索引。您可以在下面找到证明这一事实的执行计划的一部分:

"~children": [
{
  "#operator": "PrimaryScan",
  "index": "#primary",
  "keyspace": "CSM",
  "namespace": "default",
  "using": "gsi"
},
Run Code Online (Sandbox Code Playgroud)

那么,问题是 couchbase 查询优化器的行为正确且合法吗?这是否意味着查询计划不考虑参数的实际值?我是否手动将值放入查询字符串中,或​​者存在其他方式来使用 N1Ql 参数化查询和正确的索引选择?

编辑

根据shashi raj回答,我将 N1qlParams.build().adhoc(false) 参数添加到参数化 N1QL 查询中。这并不能解决我的问题,因为这个查询仍然存在性能问题。此外,当我打印查询时,我发现它与我之前描述的相同。所以,我的查询仍然分析错误并导致性能下降。

gap*_*ton 1

您的情况的问题是由于您有一个带有 'where' 子句的索引WHERE ( _class = "path/MyClass"),同时您_class在查询中将其作为参数传递。

因此,分析参数化查询的查询优化器不知道该查询可能使用为 创建的索引_class = "path/MyClass",因为它_class = $class位于 select 的 where 中。很简单,对吧?

因此,不要将索引的“where”中提到的任何字段作为选择参数传递。相反,_class = "path/MyClass"以与create index. 一切都应该很好。

这是 couchbase 问题跟踪系统中关于此问题的票证。

https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22