我不太擅长 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以消除重复行。但我不知道如何优化代码生成的请求。有人可以解释一下并提出优化建议吗?