2011-01-05 14 views
2

Ich arbeite an einer Paar Vergleich Website, wo ein Benutzer eine Liste von Filmen und Noten von einer anderen Website lädt. Meine Website wählt dann zwei zufällige Filme aus und vergleicht sie miteinander, der Benutzer wählt den besseren der beiden aus und ein neues Paar wird geladen. Dies gibt eine vollständige Liste der Filme sortiert nach dem besten.Optimierung der SQL-Abfrage in Bezug auf Paarvergleiche

Die Datenbank enthält drei Tabellen;

fm_film_data - diese enthält alle importierten Filme

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 - das alle Informationen zu einem Benutzer im Zusammenhang enthält, welche Filme der Benutzer gesehen hat, was Qualitäten der Benutzer angegeben hat, sowie Informationen zu den einzelnen Film Gewinne/Verluste für diesen Benutzer.

fm_log - dies enthält Aufzeichnungen von jedem Duell, das aufgetreten ist.

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

Um ein Paar zu holen dem Benutzer zu zeigen, ich habe eine mySQL Abfrage erstellt, der das Protokoll überprüft und ein Paar zufällig auswählt.

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 

Diese Abfrage dauert einige Zeit, etwa 6 Sekunden in unseren Tests mit zwei Benutzern mit jeweils etwa 800 Noten.

Ich bin auf der Suche nach einer Möglichkeit, dies zu optimieren, aber immer noch alle Duelle auf einmal erscheinen zu begrenzen.

Der Server läuft MySQL Version 5.0.90-Community.

Antwort

0

Haben Sie versucht, Indizes auf die Tabellen anzuwenden?

Die Spalte user_id wäre ein guter Anfang. Das ID-Feld, das auch in der WHERE-Klausel verwendet wird, wäre ein weiterer Index, der sich möglicherweise hinzufügen lässt. Benchmakr, um sicherzustellen, dass das Hinzufügen der Indizes zu Beschleunigungen führen und anderen Code nicht verlangsamen (z. B. Einfügungen).

Ich habe jedoch festgestellt, dass einfache Indizes auf kurze Tabellen wie diese immer noch zu einigen großen Geschwindigkeitssteigerungen führen können, wenn sie auf Felder in den WHERE-Klauseln der SELECT- und UPDATE-Anweisungen angewendet werden.

2

Ich denke, Sie sind besser dran, eine gespeicherte Prozedur/Funktion zu erstellen, die ein Paar zurückgibt, sobald es ein gültiges gefunden hat.

stellen Sie sicher, es gibt richtige Indizes:

  • fm_films.user_id (versuchen einschließlich der film_id auch)
  • fm_log.user_id (versuchen Sie, einschließlich der winner und 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

Dies erfordert einige ernsthafte Forschung, um zu verstehen: P –