0

我不太擅长 SQL,并且在尝试使用字段名列表 + 可能的字段值过滤产品列表时遇到了巨大的性能问题。

这是我的工作示例:

  • 过滤参数;
[
    {
        "fieldKey"   : "tags",
        "fieldValues": "tagD,tagB"
    },
    {
        "fieldKey"   :  "cats",
        "fieldValues":  "categ2,categ3"
    },
    {
        "fieldKey"   :  "infos",
        "fieldValues":  "info1"
    }
]
  • 结果列表:
[
    {
        "id": 1, 
        "name": "prod1",
        "tags": [ "tagB", "tagD", "tagI"],
        "cats": [ "categ1","categ3"],
        "infos":[ "info1", "info6"]
    }
]
  • 上市逻辑:
@Entity
@Table(name = "product")
public class Product {

    @Id Long id; 
    String name;
    @ElementCollection List<String> tags;
    @ElementCollection List<String> cats;
    @ElementCollection List<String> infos;
}

...

@PostMapping("products/search")
List<Product> getProducts(@RequestBody List<SearchCriteria> searchCrits) {

  var specification = Specification.<Product> where(null);
  for (SearchCriteria searchCrit : searchCrits) {
     specification = Specification
                    .where(specification)
                    .and( new Specification<Product>() {

    @Override
    public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, 
                                 CriteriaBuilder criteriaBuilder) {
                                    
        String fieldKey = searchCrit.getFieldKey();
        String[] fieldValues = searchCrit.getFieldValues().split(",");

        return root.join(fieldKey).in(
            Stream.of(fieldValues)
                  .map(elem -> builder.literal(elem))
                  .collect(Collectors.toList())
        );
    }
                    
                                    });
  }

  return productRepo.findAll(specification);
}
  • 生成的 SQL 请求:
SELECT DISTINCT product0_.id AS id1_0_,product0_.name AS name2_0_
FROM product product0_
INNER JOIN product_tags tags1_   ON product0_.id=tags1_.product_id
INNER JOIN product_cats cats2_   ON product0_.id=cats2_.product_id
INNER JOIN product_infos infos3_ ON product0_.id=infos3_.product_id
WHERE ( tags1_.tag   in (?,?) )
  AND ( cats2_.cat   in (?,?) )
  AND ( infos3_.info in (?)   )

SELECT ... FROM product_tags  tags0_   WHERE tags0_.product_id=?;
SELECT ... FROM product_cats  cats0_   WHERE cats0_.product_id=?;
SELECT ... FROM product_infos infos0_ WHERE infos0_.product_id=?;

(这个例子是简化的,真正的问题有10000多行)

  • 我的分析:

我猜它正在尝试对 4 个表进行笛卡尔积,然后通过过滤product_id并应用distinct以消除重复行。但我不知道如何优化代码生成的请求。有人可以解释一下并提出优化建议吗?

4

0 回答 0