我目前正在处理一个查询,它根据表的属性从表中搜索书籍。该表包含超过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风格中可用。
我目前有以下问题:
这是针对类似查询的最有效的查询类型吗?如果没有,有什么建议可以加快速度吗?
我是否应该切换到完全不同类型的数据库/引擎,例如更高效(更快)的查询?

最佳答案

最有效的方法可能是existsnot 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/

10-10 16:23