Расширенный SELECT в Mysql или несколько SELECTS? Ключевые слова фильмов

У меня есть база данных mysql с фильмами следующим образом:

ФИЛЬМЫ(идентификатор,название)

KEYWORDS_TABLE(id,key_id) [id ссылается на movie.id, key_id ссылается на keywords.id]

KEYWORDS(id,keyword) //в моем примере это не имеет значения..

В основном у меня есть фильмы с их названиями и ключевыми словами сюжета для каждого из них, я хочу выбрать все фильмы с одинаковыми ключевыми словами с заданным идентификатором фильма.

Я пробовал что-то вроде:

ВЫБЕРИТЕ key_id ИЗ таблицы ключевых слов, ГДЕ id = 9

делая это в php и сохраняя все идентификаторы в массиве $key_id.. затем я создаю еще один выбор, который выглядит так:

ВЫБЕРИТЕ фильмы.название ИЗ фильмов,таблица_ключей, ГДЕ keywords_table.key_id=$key_id[1] ИЛИ keywords_table.key_id=$key_id[2] ИЛИ ......... ИЛИ keywords_table.key_id=$key_id[n]

Это работает, но занимает слишком много времени, поскольку мы говорим о базе данных с тысячами тысяч записей.

Итак, есть предложения?? Благодарность!


person Supyxy    schedule 16.06.2010    source источник


Ответы (3)


Одна вещь, которую вы могли бы улучшить... Вместо того, чтобы писать x = a OR x = b OR x = c, вы можете сократить это до следующего: x IN (a, b, c).

SELECT movies.title
FROM movies,keywords_table
WHERE keywords_table.key_id IN ($key_id[1], $key_id[2], ..., $key_id[n])

Также обратите внимание, что в запросе отсутствует условие соединения. В настоящее время вы выполняете ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ, также известное как декартово произведение. Я думаю, вы хотите этого:

SELECT movies.title
FROM movies
JOIN keywords_table
ON movies.id = keywords_table.id
WHERE keywords_table.key_id IN ($key_id[1], $key_id[2], ..., $key_id[n])

Этот запрос может возвращать один и тот же фильм более одного раза, поэтому вы можете добавить DISTINCT, чтобы удалить дубликаты. Также вы можете сделать все это в одном запросе вместо двух в качестве дальнейшей оптимизации:

SELECT DISTINCT M.title
FROM keywords_table K1
JOIN keywords_table K2
ON K2.key_id = K1.key_id
JOIN movies M
ON K2.id = M.id
WHERE K1.id = 4

Что касается производительности, убедитесь, что первичный ключ установлен на (id) на movies и на (key_id, id) на keywords_table.

person Mark Byers    schedule 16.06.2010
comment
Объединение, вероятно, более эффективно... и не даст сбой после 2100 записей, как в другом вопросе. - person MvanGeest; 16.06.2010
comment
Я не имел в виду, что... обе операции могут быть заменены одним запросом с несколькими JOIN s - person MvanGeest; 16.06.2010
comment
И это причина, по которой использование неявного соединения плохо. Здесь произошло незамеченное перекрестное соединение. Использование неявных соединений является плохой практикой. Рад видеть, что вы используете явный синтаксис вместо того, чтобы просто исправить неявный синтаксис для удаления перекрестного соединения. - person HLGEM; 16.06.2010
comment
Удалил свой предыдущий комментарий после того, как вы его исправили. Этот последний запрос выглядит красиво. Я собираюсь проверить это прямо сейчас. - person MvanGeest; 16.06.2010
comment
Да, у меня это тоже сработало, но это занимает слишком много времени (для моей базы данных), кажется, создание списка с похожими фильмами в режиме реального времени не является хорошим выбором, я могу попробовать создать некоторые предопределенные списки с отношениями между фильмами или что-то в этом роде. .. что вы предлагаете, ребята?? - person Supyxy; 16.06.2010
comment
Извините - пришлось удалить комментарий, говоря, что это сработало. Supyxy, вы можете выполнить EXPLAIN этот запрос и указать количество rows, которое он выбирает? Он должен показать четыре шага. phpMyAdmin сделает это легко. - person MvanGeest; 16.06.2010
comment
Таблица K1 - 144 строки Таблица K2 - 21 строка Таблица M - 1 строка Ну, я не думаю, что это хорошее решение, в каждом фильме есть как минимум 50 ключевых слов, всего их около 1 миллиона, и скрипт должен проверять каждое ключевое слово. данного фильма, если есть другие фильмы с таким же ключевым словом.. это заняло около 1 минуты, лол :) - person Supyxy; 17.06.2010
comment
@Supyxy: Вы создали первичные ключи, как я предложил? Можете ли вы опубликовать свои определения таблиц? Этот запрос не должен быть таким медленным. - person Mark Byers; 17.06.2010
comment
Фильмы — id[int(8), первичный ключ, автоинкремент, уникальный], Keyword_table — id[int(8), индекс, внешний ключ movie.id] / key_id[int(8), индекс, внешний ключ keywords.id] .. я должен удалить индексы и добавить к ним первичные ключи? - person Supyxy; 17.06.2010
comment
Да, я изменил их на первичные ключи, это намного лучше, но это занимает около 5 секунд, что слишком долго. Буду искать другие методы, может быть, мне следует изменить дизайн таблиц и создать несколько предопределенных списков со связанными фильмами, например создать таблицу для каждого ключевого слова и перечислить там все фильмы. Было бы хорошо, если бы я открыл новую тему об оптимизации моей БД? - person Supyxy; 17.06.2010

Попробуйте использовать ключевое слово «in» вместо создания большого количества логических операций.

SELECT movies.title FROM movies WHERE keyword_table.key_id IN ($key_id[1],..,$key_id[n])
person sabauma    schedule 16.06.2010

Используйте подзапрос:

SELECT DISTINCT m.title
FROM movies m
WHERE id IN (
    SELECT id
    FROM keywords_table
    WHERE id = 9);
person stephenr    schedule 16.06.2010
comment
Я думаю, вам не хватает соединения. - person Mark Byers; 16.06.2010