我们的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]
还有什么需要做的吗?
答案 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/