Каков наиболее эффективный способ поиска строк в таблице на основе метаданных, хранящихся в другой таблице? - PullRequest
1 голос
/ 17 июня 2011

Рассмотрим эти две таблицы, хранящиеся в базе данных 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 голосов
/ 17 июня 2011
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 ответ .

0 голосов
/ 17 июня 2011

Посмотрите, поможет ли это:

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

...