基于存储在另一个表中的元数据搜索表中行的最有效方法是什么?

时间:2011-06-16 20:57:59

标签: mysql sql database relational-database

考虑存储在MySQL数据库中的这两个表。第一个存储电影列表,第二个存储关于每个电影的元数据。它们不是将“类别”和“演员”字段添加到电影表中,而是作为键/值对存储在movie_attributes表中,因为每个电影可能有多个类别或参与者归属于它。

id    name
-----------
0     hot rod
1     star wars

movie_attributes

id    movie_id    key      value
----------------------------------------
0     0           genre    comedy
1     0           genre    stupid
2     0           actor    andy samberg
3     0           actor    harrison ford
4     0           actor    chester tam
5     1           genre    adventure
6     1           actor    harrison ford

根据允许用户选择多个流派和多个演员的搜索条件,查询电影的最有效方法是什么?如果用户在搜索中添加了多个类别,我希望结果包含两个类别的电影(但只包括那些也与所选演员相匹配的视频。)

例如,这个伪查询:

select * from movies where (genre = 'comedy' OR genre = 'adventure') AND (actor = 'harrison ford')

会返回这个:

id    name
-----------
0     hot rod
1     star wars

目前,我的解决方案使用了大量的子查询并且速度非常慢,因为我的数据库每个电影(流派,演员,演员,标签等)包含两个以上的属性键类型,而且速度非常慢。这是真正的查询,它等同于上面的示例伪查询:

select * from movies
    WHERE (select count(*) from movie_attributes 
           WHERE key='genre'
           AND (value='comedy' 
                OR value='adventure'))>0
    AND
          (select count(*) from movie_attributes 
           WHERE key='actor' 
           AND (value='harrison ford'))>0

使用连接或其他一些我不熟悉的SQL巫术魔法是否有更有效的方法来实现相同的结果?谢谢!

2 个答案:

答案 0 :(得分:0)

看看这个是否有帮助:

SELECT m.* FROM `movie_attributes` ma
JOIN `movies` m ON (ma.movie_id=m.id)
WHERE 
  (`key` = 'genre' and `value` in ('comedy', 'adventure'))
OR (`key` = 'actor' and `value` in ('harrison ford'))

其次,请确保key, value

中的字段movie_attributes上有索引

答案 1 :(得分:0)

SELECT *
FROM movies 
WHERE EXISTS(
  SELECT NULL 
  FROM movie_attributes
  WHERE movies.id = movie_attributes.movie_id AND
        key = 'genre' AND value in ('comedy', 'adventure')
) AND 
EXISTS(
  SELECT NULL 
  FROM movie_attributes
  WHERE movies.id = movie_attributes.movie_id AND
        key = 'actor' AND value = 'harrison ford'
)

但我建议不要采用这种设计,请参阅@n8wrl answer