我目前正在处理一个查询,该查询根据表的属性从表中搜索书籍。该表包含超过5000万行,具有以下结构:
-----------------------
| book_id | attr_id |
-----------------------
| 2005207 | 35021 |
-----------------------
| 2005207 | 28106 |
-----------------------
| 2005207 | 27173 |
-----------------------
| 2005207 | 35109 |
-----------------------
| 2005207 | 34999 |
-----------------------
| 2005207 | 35107 |
-----------------------
| 2005207 | 35099 |
-----------------------
| 2005207 | 35105 |
-----------------------
| 2005207 | 28224 |
-----------------------
| ... | ..... |
-----------------------
属性列表示属性,例如绑定,发布年份,流派等等。 主键是复合键attr_id,book_id
一个示例查询可以是"查找所有书籍,其中流派是漫画或科幻小说,没有精装和#34;。
SELECT sql_no_cache a.book_id
FROM
(SELECT book_id
FROM attribute_books ab
WHERE ab.attr_id IN (38571,
38576)) a
LEFT JOIN
(SELECT book_id
FROM attribute_books ab
WHERE ab.attr_id = 35003) b ON b.book_id = a.book_id
AND b.book_id IS NULL;
这些类型的查询可以多次自我连接,目前性能非常差。我还可以使用intersect命令,而不是IN语句的内连接和NOT IN语句的左连接,这可以在某些SQL风格中使用。
我目前有以下问题:
答案 0 :(得分:1)
一种方法使用条件聚合:
SELECT book_id
FROM attribute_books
GROUP BY book_id
HAVING
SUM(CASE WHEN attr_id IN (38571, 38576) THEN 1 ELSE 0 END) > 1 AND
SUM(CASE WHEN attr_id = 35003 THEN 1 ELSE 0 END) = 0;
第一个HAVING
子句检查该类型是喜剧还是科幻小说,第二个HAVING
子句检查该书不是精装本。您可以通过添加或删除其他键值对来扩展此查询。
答案 1 :(得分:1)
最有效的方法可能是exists
和not exists
:
select b.*
from books b
where not exists (select 1
from attribute_books ab
where ab.attr_id in (38571, 38576) and b.book_id = ab.book_id
) and
exists (select 1
from attribute_books ab
where ab.attr_id = 35003 and b.book_id = ab.book_id
)
为此,您需要attribute_books(book_id, attr_id)
上的索引。