2015-04-19 12 views
5

Mam tabeli MySQL z 100k wierszy, która rejestruje kilka logi serwera utworzony jako:Update-przyłączyć MySQL bardzo powolny w porównaniu do kwerendy wybierającej bez indeksów

CREATE TABLE `logs` ( 
    `id` INT NOT NULL AUTO_INCREMENT, 
    `ip` VARCHAR(16) NULL, 
    `date` DATETIME NULL, 
    `session_time` SMALLINT UNSIGNED NULL, 
    PRIMARY KEY (`id`)); 

Próbuję obliczyć czas trwania sesji jako różnica czasu między kolejnymi rzędami tego samego adresu IP. Jestem w stanie osiągnąć z następującej kwerendy wybierającej, która zajmuje mniej niż sekundę:

SELECT * FROM logs AS a 
LEFT JOIN (
    SELECT id, 
     from_unixtime(@diff) AS starttime, 
     date AS endtime, 
     IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1, 
     @diff := unix_timestamp(date) 
    FROM logs, 
     (SELECT @diff := 0) AS x 
    ORDER BY ip, logs.date 
) AS b ON 
    a.id = b.id 

Jednak, gdy staram się korzystać z poprzedniej kwerendy w aktualizacji dołącz do aktualizacji Czas sesji, następujące zapytanie aktualizacja trwa dłużej niż 600 sekund:

UPDATE logs AS a 
LEFT JOIN (
    SELECT id, 
     from_unixtime(@diff) AS starttime, 
     date AS endtime, 
     IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1, 
     @diff := unix_timestamp(date) 
    FROM logs, 
     (SELECT @diff := 0) AS x 
    ORDER BY ip, logs.date 
) AS b ON 
    a.id = b.id 
SET session_time = session_time1; 

Czego mi brakuje?

Dzięki!

UPDATE: Oto EXPLAIN z select:

+----+-------------+------------+--------+---------------+------+--------+ 
| id | select_type | table | type | possible_keys | key | rows | 
+----+-------------+------------+--------+---------------+------+--------+ 
| 1 | PRIMARY  | a   | ALL | NULL   | NULL | 109029 | 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL | 108680 | 
| 2 | DERIVED  | <derived3> | system | NULL   | NULL | 1  | 
| 2 | DERIVED  | logs  | ALL | NULL   | NULL | 109029 | 
| 3 | DERIVED  | NULL  | NULL | NULL   | NULL | NULL | 
+----+-------------+------------+--------+---------------+------+--------+ 
+1

'GDZIE ip =" ... "'? Wygląda na to, że aktualizujesz wszystkie wpisy 100k, ale te, które wybierasz ("LEFT JOIN" = elementy, które nie są zgodne z wybranymi regułami w pierwszej grupie). Spróbuj użyć 'INNER JOIN'? –

+0

Dzięki Alejandro, ale nie do końca rozumiem twój komentarz. Dlaczego połączenie wewnętrzne byłoby lepsze? Co masz na myśli mówiąc o klauzuli "where"? – kahlo

+0

Przepraszam, powinienem był to lepiej wyjaśnić. Kiedy używasz 'UPDATE', zwykle używasz klauzuli" WHERE "do filtrowania, które dane powinny być aktualizowane. W twoim przypadku, jeśli chcesz zaktualizować pod konkretny adres IP, "WHERE ip =" "powinno być lepiej przetwarzać tylko dane z tym konkretnym adresem IP (myślę, że twoje zapytanie przetwarza każdy rekord w twojej tabeli , nawet jeśli nie wszystkie z nich są aktualizowane). –

Odpowiedz

0

rozpocząć się session_time będąc NULL we wszystkich rzędach. Zmienić zapytanie na dwa sposoby:

  • Dodaj WHERE session_time IS NULL z aktualizacją (na końcu)
  • Zestaw session_time do NULL jeśli nie masz czasu zamknięcia, jeszcze ustawić go prawidłowo.

Pierwsza noc będzie tak powolna jak teraz, ale potem będzie znacznie szybciej, ponieważ będzie działać tylko na kilku "nowych" rzędach.

Edit

A JOIN potrzeby (zazwyczaj) klauzula ON. Jak o połączeniu logs i a z PRIMARY KEY z logs. The EXPLAIN pokazują, że musi przebiegać przez kombinacje 109K * 108K z logs i a; powinno być tylko 109K.

Usunąć także LEFT, chyba że jest to potrzebne.

+0

Dzięki Rick, dodałem twoją sugestię. Jednak tamto zapytanie zawiera już tylko nowe informacje wygenerowane w jeden dzień (100 tys. Wierszy dziennie). Nadal jestem zaintrygowany tym, co może powodować taką różnicę czasu i ją naprawiać. – kahlo

+0

Jeśli używasz wersji 5.6, opublikuj "WYBIERZ WYBIERZ ..." i "WYKORZYSTAJ AKTUALIZACJĘ ...". Być może to pokaże, że optymalizator robi między nimi coś innego. –

+0

Właśnie dodałem EXPLAIN SELECT ... ale nie mogę dodać "EXPLAN UPDATE ..." ponieważ używam wersji 5.5.29, a poprzednie 5.6.3 było niedozwolone. – kahlo

Powiązane problemy