2015-09-17 13 views
5

Mam kwerendę, która pobiera zapisy 2. najwyższą datę z db. Moje zapytanie działa dobrze, ale wykonanie zajmuje zbyt wiele czasu. Jak mogę szybko wykonać moje zapytanie.Dlaczego moje zapytanie mysql działa wolno?

+2

dobre pytanie. Użyj EXPLAIN przed zapytania, aby zobaczyć co jest nie tak, lub opublikować wynik –

+0

@BerndBuffen postaram go – sunny

+0

opublikować Wynik to mogę spojrzeć –

Odpowiedz

2

Podejdę do tego nieco inaczej niż inni ... Czy brakuje mi czegoś lub oprócz oczywistych optymalizacji indeksowania, które wszystkie twoje połączenia są na podstawowych kluczyach do wyszukiwań - czy twoje kryteria są dokładne?

Oto, co mam na myśli ... Twoja ostatnia klauzula WHERE ..

WHERE 
     r.client_id IN (SELECT opinion_id 
          FROM pacra_client_opinion_relations 
          WHERE client_id = 50) 

Pytasz dla CLIENT_ID będąc w wybranej wyniku OPINION_ID ale tylko patrząc na opinii dla CLIENT_ID = 50. Jaki jest kontekst Opinion_id.

wyjaśnienie Klienta vs opinii z tabeli „pacra_client_opinion_relations” Spójrzmy na przykładowe dane jak poniżej

Opinion_ID Client_ID Other... 
1    28   ... 
2    35   ... 
3    50   ... 
4    2   ... 
5    50   ... 
6    6   ... 
7    50   ... 
8    4   ... 

Jeśli zapytanie jest dla wszystkich OPINION_IDs client_id = 50, to wrócisz OPINION_ID # s 3, 5 i 7. Ponieważ twoja klauzula where pyta o CLIENT_ID w wybranych opiniach, teraz przechwytujesz dane dla klientów 3, 5 i 7 i nie masz nic wspólnego z klientem # 50, na który zacząłeś patrzeć.

Również ... jeśli szukasz tylko rzeczy z "Client_ID = 50", wtedy twoje poprzednie pytania próbujące uzyskać SECOND do najnowszej daty powiadomienia, pytasz WSZYSTKICH klientów. Jeśli dodasz klauzulę where dla "Client_ID = 50", otrzymasz tylko te, a nie drugie do ostatniego powiadomienia WSZYSTKICH klientów.

Aby wyjaśnić wartość MAX() mniej niż wewnętrzna wartość MAX(). Ex dane z oceny co można uzyskać następujące ...

og_ratings (assuming this data is pre-sorted per client for sample purposes) 
client_id notification_date 
13   Sep 5  <- You want THIS entry if it was client 13 included 
13   Sep 14  <- Most recent for client 13 
28   Sep 1 
28   Sep 8 
28   Sep 10  <- You want THIS entry if client 28 included 
28   Sep 11  <- Most recent for client 28 
29   Sep 4  <- You want THIS entry if client 29 included 
29   Sep 11  <- Most recent for client 29 
43   Sep 16  <- Most recent for client 43 and no prior, 
         this would never show as only one entry for client 
50   Sep 2 
50   Sep 9 
50   Sep 12  <- You want THIS entry for client 50 
50   Sep 15  <- Most recent for client 50 

podstawie przykładowych danych, co można uzyskać ... różnych klientów może mieć wyraźnie różną 2P najnowszych dat

client_id notification_date 
13   Sep 5 
28   Sep 10 
29   Sep 4 
50   Sep 12 

Jeśli wszystko W zadaniu OUTERMOST dbałeś o klienta 50, a twoje rzeczywiste dane zawierały setki klientów (lub nawet tysiące klientów), pytasz WSZYSTKICH klientów. Można ograniczyć swoją wewnętrzną zapytanie specjalnie dla klienta 50 przez ...

og_ratings r INNER JOIN (
    SELECT 
     client_id, 
     max(notification_date) notification_2nd_date 
    FROM 
     og_ratings 
    WHERE 
     (client_id, notification_date) 
     NOT IN (SELECT client_id, max(notification_date) 
        FROM og_ratings 
        GROUP BY client_id) 
    GROUP BY 
     client_id 
    ORDER BY 
     client_id DESC 

mogą być dostosowane do ...

og_ratings r INNER JOIN (
    SELECT 
     client_id, 
     max(notification_date) notification_2nd_date 
    FROM 
     og_ratings 
    WHERE 
     client_id = 50 <--- ADDED TO WHERE CLAUSE for CLIENT 50 ONLY 
     AND (client_id, notification_date) 
     NOT IN (SELECT client_id, max(notification_date) 
        FROM og_ratings 
        WHERE client_id = 50 <--- ADDED HERE TOO FOR CLIENT 50 
        GROUP BY client_id) 
    GROUP BY 
     client_id 
    ORDER BY 
     client_id DESC 

i to tylko zwróci pojedynczy rekord dla klienta 50 vs dat dla ALL klienci

client_id notification_date 
50   Sep 12 

Wreszcie, w wielu czasach oferując zapytań MySQL, jakie oferowane pomocą STRAIGHT_JOIN słowa kluczowego. To zasadniczo mówi MySQL do zapytania w kolejności, w której to powiedziałeś ... Czasami, kiedy (jak na przykład twoja sprawa), masz masę tabel odnośników, to może próbujesz myśleć za ciebie i najpierw użyć tabeli odnośników z powodu niskiego poziomu liczba rekordów (lub jakkolwiek/nie) stosuje zapytanie.

SELECT STRAIGHT_JOIN ... reszta zapytania

Jeśli jestem dokładna moich założeń, bardziej uproszczona zapytanie może być również wykonane, jestem po prostu staramy się wyjaśnić różne kawałki, które uważam za wątpliwe ... Wreszcie, jak widzisz przykładowe dane, które masz, gdybyś mógł przygotować przykładowe dane na temat tego i przyszłości tego, co masz i co próbujesz uzyskać, może pomóc ...

+0

Mój 'identyfikator_klienta' mający wiele' opinii_id'. Twoja odpowiedź jest dobra, ale trudno mi ją zrozumieć, ponieważ jestem bardzo nowy w kodowaniu. – sunny

+0

@sunny, poprawiono moją odpowiedź ... zobacz, czy wyjaśnienia pomagają ci i mojej interpretacji danych oraz tego, co WYGLĄDASZ, czego szukasz. – DRapp

+0

, ale chcę wszystkie rekordy przeciwko client_id.As wiesz, że Mój client_id ma wiele opinion_id. Chcę pobrać cały rekord opinion_id przeciwko client_id. W tym możesz mi pomóc? – sunny

0

poniższe pola powinny być indeksowane, aby uzyskać od wyników

Table : og_ratings 

notification_date 
pacra_action 
pacra_outlook 
pacra_lterm 
pacra_sterm 

Możesz spróbować z indywidualnym lub w połączeniu indeksu za pomocą którego można uzyskać lepszą wydajność.

Jeśli pokażesz całą strukturę tabel ze szczegółami indeksu, możesz pomóc Ci lepiej.

Aktualizacja dla tworzenia indeksu:

alter table og_ratings 
add index idx_pacra_action(pacra_action), 
add index idx_pacra_outlook(pacra_outlook), 
add index idx_pacra_lterm(pacra_lterm), 
add index idx_pacra_sterm(pacra_sterm); 

2-te Edycja ze względu na zmiany w logice zapytanie:

Właściwie zapytanie jest logicznie nie jest poprawny, jak jesteś wiązana przekazać 2 parametrów nie w klauzuli takiej jak where (client_id, notification_date) not in (SELECT client_id, MAX(notification_date) FROM og_ratings GROUP BY client_id)

Więc sprawdź poniżej zapytanie, czy zapewnia pożądane wyniki i powinno być szybkie-

SELECT r.client_id,c.id,t.id,a.id,o.id,c.name AS opinion, r.notification_date, t.title AS ttitle,a.title AS atitle,o.title AS otitle, l.title AS ltitle, s.title AS stitle, r.opinion_id, pc.id, r.pr_client_id AS pr_client, pc.address, pc.liaison_one, city.id, pc.head_office_id, city.city, pc.title AS cname 
FROM (SELECT a.client_id, a.notification_date, a.rating_type_id, a.pacra_action, a.pacra_outlook, a.pacra_lterm, a.pacra_sterm, a.opinion_id, a.pr_client_id 
FROM (SELECT t.client_id, t.notification_date, t.rating_type_id, t.pacra_action, t.pacra_outlook, t.pacra_lterm, t.pacra_sterm, pr.opinion_id, pr.client_id AS pr_client_id, 
       CASE 
       WHEN @category != t.client_id THEN @rownum := 1 
       ELSE @rownum := @rownum + 1 
       END AS rank, 
       @category := t.client_id AS var_category 
      FROM og_ratings t 
      JOIN pacra_client_opinion_relations pr ON pr.opinion_id = r.client_id 
      JOIN (SELECT @rownum := NULL, @category := '') r 
      WHERE pr.client_id = 50 
      ORDER BY t.client_id,t.notification_date DESC) a 
     WHERE x.rank=2) r 
LEFT JOIN og_companies c ON r.client_id = c.id 
LEFT JOIN og_rating_types t ON r.rating_type_id = t.id 
LEFT JOIN og_actions a ON r.pacra_action = a.id 
LEFT JOIN og_outlooks o ON r.pacra_outlook = o.id 
LEFT JOIN og_lterms l ON r.pacra_lterm = l.id 
LEFT JOIN og_sterms s ON r.pacra_sterm = s.id 
LEFT JOIN pacra_clients pc ON pc.id = r.pr_client_id 
LEFT JOIN city ON city.id = pc.head_office_id 

Ponieważ nie wykonałem tego zapytania, więc jeśli pojawi się błąd składniowy itp., Możesz utworzyć sqlfiddle, aby móc go poprawić.

+0

Co masz na myśli? Jak mogę podrzucić ci moje indeksy? Czy możesz mi powiedzieć. jestem gotowy, aby pokazać wszystkie indeksy, ale w jaki sposób? Potrzebuję pomocy – sunny

+4

@sunny https://dev.mysql.com/doc/refman/5.0/en/show-index.html Twoje życie będzie o wiele łatwiejsze dzięki wyszukiwarkom :) – Jonast92

+0

@ Jonast92 Używam tego linku i mogę opublikować indeks mojego stolika w moim pytaniu – sunny

0

dodawania indeksu do swoich pól referencyjnych kolumn, które mam na myśli w ON część jak r.client_id, c.id

LEFT JOIN og_companies c ON r.client_id = c.id 
    LEFT JOIN og_rating_types t ON r.rating_type_id = t.id 
    LEFT JOIN og_actions a ON r.pacra_action = a.id 
    LEFT JOIN og_outlooks o ON r.pacra_outlook = o.id 
    LEFT JOIN og_lterms l ON r.pacra_lterm = l.id 
    LEFT JOIN og_sterms s ON r.pacra_sterm = s.id 
    LEFT JOIN pacra_client_opinion_relations pr ON pr.opinion_id = c.id 
    LEFT JOIN pacra_clients pc ON pc.id = pr.client_id 
    LEFT JOIN city ON city.id = pc.head_office_id 

tak jak można dodać indeks na mysql?

SQL >>ALTER TABLE your_table_name ADD INDEX (your_column_name);

także dla lepszej wydajności dołączyć kolumny powinny mieć taką samą strukturę. Na przykład, jeśli twoja kolumna_1 jest int (11) niepodpisana, druga strona powinna być taka sama.

  • Upewnij masz indeksów dla wszystkich kolumn, które są częścią tabeli dołącza
  • Upewnij masz indeksów na dowolnej kolumny używane w filtrze
  • jawnie zdefiniować klucze podstawowe Jednoznaczne zdefiniowanie klucza obcego relacji
  • w przypadku dużych zbiorów danych, wykorzystanie partycjonowania tabeli Definiowanie kolumn jako NOT NULL w miarę możliwości

http://kb.tableau.com/articles/knowledgebase/database-query-performance

Powiązane problemy