在多对多关系中进行复杂搜索的最快SQL表达式?

| 在product_tag表中,这些列是   id,product_id,tag_id 如果我要搜索的产品是tag1或tag2或tag3,则直接方法是:
SELECT DISTINCT productId FROM product_tags WHERE tagId IN (2,4);
如果我要搜索的产品是tag1 AND tag2 AND tag3,则直接方法是:
SELECT productId FROM product_tag WHERE tag_id IN (tag1, tag2, tag3) GROUP BY productId HAVING COUNT(*) = 3
但是问题是我是否要搜索具有复杂标签关系的产品,例如:   (tag1或tag2或tag3)的产品   AND(标签4或tag5 OR标签6)AND(标签   7 OR tag8 OR tag9) 什么是性能最佳的SQL表达式? (最好是优雅的)。 编辑: 性能上最重要的提升是添加索引,如评论中的Remus所建议。     
已邀请:
您真的不能直接使用基于集合的语言(例如SQL)来执行此操作。 除非您没有(productId,tagId)的重复项,否则您简单的\“ AND \”版本也将无法使用。 对于复杂的关系,有必要将您的查询分为几个子查询。首先破坏所有\“ AND \”子句:
WHERE tag_id IN (tag1, tag2, tag3)
WHERE tag_id IN (tag4, tag5, tag6)
WHERE tag_id IN (tag7, tag8, tag9)
然后对查询结果进行相交。 如果这些子查询中的任何一个都不是简单的OR \'列表,而是在更复杂的逻辑结构中包含AND \,则需要进一步递归分解这些子查询。 换句话说,您可以通过\“ AND \”子句递归分解逻辑树,然后在每个树级别对查询结果进行INTERSECT。 这样做可能比生成一个大型SQL一次就能返回结果的速度要快得多,因为每个简单的OR \ ed列表都可以利用tag_id上的索引。     
合并所有3组。它们是3个选择,但它们确实很简单。     
性能不会那么好,但是您可以执行嵌套查询
SELECT 
ProductID FROM
Products 
WHERE tag_id IN (tag1, tag2, tag3)
AND ProductID IN (
SELECT 
ProductID FROM
Products 
WHERE tag_id IN (tag4, tag5, tag6)
)
AND ProductID IN (
SELECT 
ProductID FROM
Products 
WHERE tag_id IN (tag7, tag8, tag9)
)
    
我注意到在不同的行上选择满足不同条件的值? 怎么样
SELECT DISTINCT t1.productId FROM product_tags t1
JOIN product_tags t2 ON t1.productId=t2.productId AND t2.tagId IN (tag4,tag5,tag6)
JOIN product_tags t3 ON t1.productId=t3.productId AND t3.tagId IN (tag7, tag8, tag9)
AND t1.tagId IN (tag1,tag2,tag3)
如果能以某种方式除去ѭ5,那会更好。     
是否预先知道标签数量?如果不是随着时间的流逝,我将把tag_id更改为一个位集。
WITH T AS 
 (SELECT product_id, bit_or((1<<tag_id)::bigint) tagset 
  FROM product_tag GROUP BY product_id) 
SELECT product_id 
WHERE (tagset & 7)>0 AND (tagset & 56)>0 AND (tagset & 448)>0;
我在这里使用过Postgres,其中&称为按位AND; bit_or是一个聚合函数(假设product_tag表中不允许有重复项,SUM在这里也可以正常工作)。掩码中的幻数只是2的幂的位或。双冒号是Postgres演员表。这里的所有内容在其他地方都应该以稍微不同的名称提供。但是PG也具有不确定大小的位串,并且可以为大量标签实现与位串相同的逻辑。 顺便说一下,匹配所有标签的情况仅为
(tagset & mask)=mask
。 实际上,这就是为什么您的索引运行如此之快的原因。他们可能正在被合并到这种类型的测试中。     

要回复问题请先登录注册