我目前正在处理一个查询,它根据表的属性从表中搜索书籍。该表包含超过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
一个例子可以是“查找所有书籍,其中的类型或漫画或科幻没有精装本”。
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;
这类查询可以多次自连接,目前性能非常差。与in语句的内部连接和not in语句的左连接不同,我还可以使用intersect命令,该命令在某些sql风格中可用。
我目前有以下问题:
这是针对类似查询的最有效的查询类型吗?如果没有,有什么建议可以加快速度吗?
我是否应该切换到完全不同类型的数据库/引擎,例如更高效(更快)的查询?
最佳答案
最有效的方法可能是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)
上的索引。关于mysql - 单表SELF JOIN替代/除/相交,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49289413/