【问题标题】:How to use secondary index for spring data correctely如何正确使用弹簧数据的二级索引
【发布时间】:2019-06-01 14:17:01
【问题描述】:

我有一个名为 order 的 couchbase 存储桶,其中包含近 2000 个文档,我为此存储桶创建了一个二级索引 (idx_customer) 以优化我的查询:

在 couchbase 查询监视器中执行时,查询命中索引。

但我认为从 spring 数据存储库播放时它错过索引。 主要是因为存储库中的排序和分页使我的查询在其他错过索引的查询中翻译。

CREATE INDEX idx_customer ON `order` (
buyer.contact.firstName , 
buyer.contact.lastName , 
ALL DISTINCT ARRAY aoc.`communicationValue` FOR aoc IN buyer.contact.communicationChannel
WHEN aoc.`communicationChannelCode`= "EMAIL" END)
WHERE _class = "com.lbk.entities.OrderEntity"

我使用带有此存储库的 spring 数据在我的 spring boot 应用程序中查询订单:

import com.lbk.entities.OrderEntity;
import com.lbk.entities.OrderMetadataEntity;
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.ViewIndexed;
import org.springframework.data.couchbase.repository.CouchbasePagingAndSortingRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

@ViewIndexed(designDoc = "orderEntity")
@N1qlSecondaryIndexed(indexName = "idx_customer")
@N1qlPrimaryIndexed
public interface OrdersRepository extends CouchbasePagingAndSortingRepository<OrderEntity, String> {

    List<OrderMetadataEntity> findAllBy();

    Page<OrderMetadataEntity> findAllBy(Pageable page);

    @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} "
                    + "AND orderTypeCode = $1 "
                    + "AND (orderCategory != $2 OR orderCategory is not valued ) "
                    + "AND buyer.contact.firstName is not null"
    )
    Page<OrderMetadataEntity> findOrders(String orderTypeCode, String excludedOrderCategory, Pageable page);

    @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} "
                    + "AND creationDateTime >= STR_TO_MILLIS($1) AND creationDateTime <= STR_TO_MILLIS($2) "
                    + "AND orderTypeCode = $3 "
                    + "AND (orderCategory != $4 OR orderCategory is not valued )"

+ "AND Buyer.contact.firstName 不为空" ) 页面 findOrdersByCreationDateTimeBetween( 字符串开始, 字符串结束, 字符串 orderTypeCode, 字符串排除订单类别, 可分页页面 );

}

但性能和日志记录表明我没有使用索引 怎么了?以及如何从我的存储库中正确查询二级索引?

对于这个分页的 N1QL 查询:

@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} "
                                + "AND orderTypeCode = $1 "
                                + "AND (orderCategory != $2 OR orderCategory is not valued ) "
                                + "AND buyer.contact.firstName is not null")
Page<OrderMetadataEntity> findOrders(String orderTypeCode, String excludedOrderCategory, Pageable page);

我在日志中有流动的三个查询:

  1. 查询文档计数。
  2. 查询以获取文档的第一页。
  3. 查询获取子文档 (SELECT ARRAY_LENGTH(orderLineItem))(我想知道为什么!!!)。

这里是spring数据日志:

Executing N1QL query: {\"args\":[\"%mohammed%\",\"%mohammed%\",null,\"220\",\"EXECLUDED_CATEGORY\"],\"statement\":\"SELECT COUNT(*) AS count FROM `order` WHERE `_class` = \\"com.lbk.entities.OrderEntity\\" AND ( LOWER(buyer.contact.firstName) LIKE $1 OR LOWER(buyer.contact.lastName) LIKE $2 OR ANY communicationChannel IN buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue  = $3 ) END )  AND orderTypeCode = $4 AND (orderCategory != $5 OR O2.orderCategory is not valued )AND creationDateTime in (select RAW max(O2.creationDateTime) from `order` O2 WHERE ( LOWER(O2.buyer.contact.firstName) LIKE $1 OR LOWER(O2.buyer.contact.lastName) LIKE $2 OR ANY communicationChannel IN O2.buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue  = $3 ) END )  AND ANY communicationChannel IN O2.buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue is not null ) END AND O2.orderTypeCode = $4 AND (O2.orderCategory != $5 OR O2.orderCategory is not valued) group by ( ARRAY item.communicationValue FOR item IN O2.buyer.contact.communicationChannel WHEN item.communicationChannelCode = 'EMAIL' END ) )AND buyer.contact.firstName IS NOT NULL\",\"scan_consistency\":\"statement_plus\"}
Executing N1QL query: {\"args\":[\"%mohammed%\",\"%mohammed%\",null,\"220\",\"EXECLUDED_CATEGORY\"],\"statement\":\"SELECT META(`order`).id AS _ID, META(`order`).cas AS _CAS, `order`.* FROM `order` WHERE `_class` = \\"com.lbk.entities.OrderEntity\\" AND ( LOWER(buyer.contact.firstName) LIKE $1 OR LOWER(buyer.contact.lastName) LIKE $2 OR ANY communicationChannel IN buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue  = $3 ) END )  AND orderTypeCode = $4 AND (orderCategory != $5 OR O2.orderCategory is not valued )AND creationDateTime in (select RAW max(O2.creationDateTime) from `order` O2 WHERE ( LOWER(O2.buyer.contact.firstName) LIKE $1 OR LOWER(O2.buyer.contact.lastName) LIKE $2 OR ANY communicationChannel IN O2.buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue  = $3 ) END )  AND ANY communicationChannel IN O2.buyer.contact.communicationChannel SATISFIES ( communicationChannel.communicationChannelCode = 'EMAIL' AND communicationChannel.communicationValue is not null ) END AND O2.orderTypeCode = $4 AND (O2.orderCategory != $5 OR O2.orderCategory is not valued) group by ( ARRAY item.communicationValue FOR item IN O2.buyer.contact.communicationChannel WHEN item.communicationChannelCode = 'EMAIL' END ) )AND buyer.contact.firstName IS NOT NULL ORDER BY `creationDateTime` DESC LIMIT 18 OFFSET 0\",\"scan_consistency\":\"statement_plus\"}
Executing N1QL query: {\"args\":[\"069cf983-8ed7-4b8f-845d-175593d4ca49\"],\"statement\":\"SELECT ARRAY_LENGTH(orderLineItem) FROM `order` WHERE `_class` = \\"com.lbk.entities.OrderEntity\\" AND META().id = $1\",\"scan_consistency\":\"statement_plus\"}

谢谢

【问题讨论】:

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


    【解决方案1】:

    查询将无法使用 idx_customer 索引,因为它不符合条件。请 查看https://blog.couchbase.com/n1ql-practical-guide-second-edition中的“在 Couchbase N1QL 中为查询设计索引”

    索引是部分索引,并且只有具有 _class= "com.lbk.entities.OrderEntity" 的文档的条目,但您的所有查询都不会包含此谓词,因此它不能使用该索引。此外,查询谓词(谓词的每个 OR 部分)必须使用前导索引键作为查询谓词才能使用索引。日志中的查询不是这种情况。如果你愿意,你可以尝试非部分索引。

    CREATE INDEX idx_customer1 ON `order` (_class, 
    buyer.contact.firstName , 
    buyer.contact.lastName , 
    ALL DISTINCT ARRAY aoc.`communicationValue` FOR aoc IN buyer.contact.communicationChannel
    WHEN aoc.`communicationChannelCode`= "EMAIL" END);
    

    【讨论】:

    • 当我在查询监视器中解释时,我的所有查询都符合索引的条件,_class= "com.lbk.entities.OrderEntity" 由我的前 2 个日志的 spring 数据添加。前导索引键被添加到所有查询中
    • 使用您建议的索引,我得到了相同的性能。感谢您的帮助
    • 将此查询与您的索引一起使用:SELECT META(order).id AS _ID, META(order).cas AS _CAS, order.* FROM order WHERE @987654327 @ = "com.lbk.entities.OrderEntity" AND orderTypeCode = '220' AND (orderCategory != 'EXCLUDED' OR orderCategory is not valued ) AND Buyer.contact.firstName 不为空 ORDER BY creationDateTime DESC 它需要经过: 6.20 秒 |执行:6.20s |计数:2345 |尺寸:80916114
    • 创建索引 idx_customer2 ON order (orderTypeCode,creationDateTime DESC) WHERE _class= "com.lbk.entities.OrderEntity"
    • 非常感谢Vsr,我终于认为即使我的查询命中了索引,使用spring-data也可能是个坏主意
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    相关资源
    最近更新 更多