Оптимизация SQL-запроса относительно парных сравнений - PullRequest
2 голосов
/ 05 января 2011

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

База данных содержит три таблицы:

fm_film_data - содержит все импортированные фильмы

fm_film_data(id int(11), 
             imdb_id varchar(10), 
             tmdb_id varchar(10), 
             title varchar(255),     
             original_title varchar(255),    
             year year(4),
             director text,
             description text,
             poster_url varchar(255))

fm_films - этосодержит всю информацию, относящуюся к пользователю, какие фильмы он просмотрел, какие оценки дал пользователь, а также информацию о выигрышах / проигрышах каждого фильма для этого пользователя.

fm_films(id int(11),
         user_id int(11),
         film_id int(11),
         grade int(11),  
         wins int(11),   
         losses int(11))

fm_log - содержит записикаждой произошедшей дуэли.

fm_log(id int(11),
       user_id int(11),
       winner int(11),
       loser int(11))

Чтобы выбрать пару для отображения пользователя, я создал запрос mySQL, который проверяет журнал и выбирает пару случайным образом.

SELECT pair.id1, pair.id2 
FROM
    (SELECT part1.id AS id1, part2.id AS id2 
    FROM fm_films AS part1, fm_films AS part2 
    WHERE part1.id <> part2.id 
        AND part1.user_id = [!!USERID!!] 
        AND part2.user_id = [!!USERID!!]) 
AS pair
LEFT JOIN
    (SELECT winner AS id1, loser AS id2 
    FROM fm_log
    WHERE fm_log.user_id = [!!USERID!!]
    UNION
    SELECT loser AS id1, winner AS id2 
    FROM fm_log
    WHERE fm_log.user_id = [!!USERID!!])
AS log
ON pair.id1 = log.id1 AND pair.id2 = log.id2
WHERE log.id1 IS NULL
ORDER BY RAND()
LIMIT 1

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

Я ищу способ оптимизировать этот процесс, но все же ограничить показ всех дуэлей только один раз..

На сервере работает сообщество MySQL версии 5.0.90.

Ответы [ 2 ]

2 голосов
/ 05 января 2011

Я думаю, вам лучше создать хранимую процедуру / функцию, которая будет возвращать пару, как только она найдет действительную.

Убедитесь, что есть правильные индексы:

  • fm_films.user_id (попробуйте включить также film_id)
  • fm_log.user_id (попробуйте включить winner и loser)

DELIMITER $$

DROP PROCEDURE IF EXISTS spu_findPair$$

CREATE PROCEDURE spu_findPair
(
    IN vUserID INT
)
BEGIN
    DECLARE done BOOLEAN DEFAULT FALSE;
    DECLARE vLastFilmID INT;
    DECLARE vCurFilmID INT;
    DECLARE cUserFilms CURSOR FOR
        SELECT id
        FROM fm_films
        WHERE user_id  = vUserID
        ORDER BY RAND();
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=TRUE;
    OPEN cUserFilms;
    ufLoop: LOOP
        FETCH cUserFilms INTO vCurFilmID;
        IF done THEN
            CLOSE cUserFilms;
            LEAVE ufLoop;
        END IF;
        IF vLastFilmID IS NOT NULL THEN
            IF NOT EXISTS
                (
                    SELECT 1
                    FROM fm_log
                    WHERE user_id  = vUserID
                        AND ((winner = vCurFilmID AND loser = vLastFilmID) OR (winner = vLastFilmID AND loser = vCurFilmID))
                ) THEN

                CLOSE cUserFilms;
                LEAVE ufLoop;
                #output
                SELECT vLastFilmID, vCurFilmID;
            END IF;
        END IF;
    END LOOP;

END$$

DELIMITER ;
0 голосов
/ 05 января 2011

Вы пытались применить какие-либо индексы к таблицам?

Хорошим началом были бы столбцы user_id.Поле id, которое также используется в предложении WHERE, может быть другим индексом, который может стоить добавить.Benchmakr, чтобы убедиться, что добавление индексов приводит к ускорению и не замедляет другой код (например, вставки).

Тем не менее, я обнаружил, что простые индексы на таких коротких таблицах могут привести к огромнымускоряется, когда они применяются к полям в предложениях WHERE операторов SELECT и UPDATE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...