在Couchbase中调用带有分页的删除文档时,Spring数据“ TimeoutException”

时间:2018-11-18 14:53:52

标签: java spring-boot spring-data couchbase n1ql

我们的Spring Boot应用正在使用Couchbase数据库,并使用Spring-Data

访问它

要从存储桶中删除记录,我们在存储库中创建了以下方法:

Slice<Dog> deleteAllByOwnerIdAndName(String ownerId, String name, Pageable pageable);

我们在存储桶上也有相关的索引:

CREATE INDEX `dogs_by_ownerId_and_name_idx` ON `dogs`(`ownerId`,`name`) WHERE (`_class` = "com.example.Dog")

我们的代码在尝试删除元素时使用分页:

 Slice<Dog> dogsSlice = null;
 Pageable pageable = PageRequest.of(0, 1000, Sort.by("id"));
 int pageCounter = 0;
 do {
   log.debug("Deleting page No. {} of dogs", pageCounter++);
   dogsSlice = dogsRepository.deleteAllByOwnerIdAndName("3243242", "Max", pageable);
 } while (dogsSlice.hasNext());

但是,太多次我们得到Timeoutexceptioin

  

删除狗的第0页

     

o.s.s.s.TaskUtils $ LoggingErrorHandler:计划任务发生意外错误。

     

org.springframework.data.couchbase.core.CouchbaseQueryExecutionException:由于出现以下n1ql错误而无法执行查询:   {“ msg”:“超过7.5秒超时”,“代码”:1080}           在org.springframework.data.couchbase.core.CouchbaseTemplate.findByN1QL(CouchbaseTemplate.java:458)〜[classes!/:5.1.40]           在org.springframework.data.couchbase.repository.query.AbstractN1qlBasedQuery.executeSliced(AbstractN1qlBasedQuery.java:189)〜[classes!/:5.1.40]           在org.springframework.data.couchbase.repository.query.AbstractN1qlBasedQuery.executeDependingOnType(AbstractN1qlBasedQuery.java:129)〜[classes!/:5.1.40]           在org.springframework.data.couchbase.repository.query.AbstractN1qlBasedQuery.execute(AbstractN1qlBasedQuery.java:106)〜[classes!/:5.1.40]           在org.springframework.data.repository.core.support.RepositoryFactorySupport $ QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:590)〜[classes!/:5.1.40]           在org.springframework.data.repository.core.support.RepositoryFactorySupport $ QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.data.couchbase.repository.support.ViewPostProcessor $ ViewInterceptor.invoke(ViewPostProcessor.java:87)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)〜[classes!/:5.1.40]           在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)〜[classes!/:5.1.40]           在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)〜[classes!/:5.1.40]           在com.sun.proxy。$ Proxy130.deleteAllByOwnerIdAndName(未知来源)〜[na:na]

还有什么需要做的吗?

3 个答案:

答案 0 :(得分:1)

您可以改善以下几点:

1)更改索引以按ownerId排序,然后在删除时也按ownerId排序

CREATE INDEX `dogs_by_ownerId_and_name_idx` ON `dogs`(`ownerId` ASC,`name`) WHERE (`_class` = "com.example.Dog") 

由于您的索引已经排序,因此在删除期间,couchbase不会花费额外的时间对其进行排序。

2)您真的需要返回所有已删除的对象吗?在将文档发送回给您之前,Couchbase必须带走索引中没有的所有属性,并且此操作将花费一些额外的时间。最好的方法是只返回ID。

@Override
public void updateFamilyName(String familyName, String familyId) {

    String queryString = "Delete from "+getBucketName()+" WHERE "+getClassFilter()+" " +
            " and familyId = '"+familyId+"' RETURNING meta().id";

    N1qlParams params = N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS).adhoc(true);
    ParameterizedN1qlQuery query = N1qlQuery.parameterized(queryString, JsonObject.create(), params);
    checklistRepository.getCouchbaseOperations().getCouchbaseBucket().query(query);
}

private String getBucketName(){
    return checklistRepository.getCouchbaseOperations().getCouchbaseBucket().bucketManager().info().name();
}

private String getClassFilter(){
    return "_class = '" + Checklist.class.getName() + "' ";
}

3)您也可以改善分页,但我认为您的情况没有必要。

https://blog.couchbase.com/offset-keyset-pagination-n1ql-query-couchbase/

答案 1 :(得分:1)

Sort.by("id")导致查询延迟,因为Couchbase似乎正在根据该条件对整个文档集合进行排序。

因此,如果没有真正的需要对结果进行排序,则最好使用

Pageable pageable = PageRequest.of(0, 1000);

答案 2 :(得分:1)

如果查询具有ORDER BY,则如果可能的话,优化程序将尝试使用索引顺序。如果不可能,则必须生成所有可能的数据集,并对数据进行排序以满足查询,即使分页需要很少的内容。

检查规则#7 https://blog.couchbase.com/create-right-index-get-right-performance/

另请参阅本文https://blog.couchbase.com/offset-keyset-pagination-n1ql-query-couchbase/