2016-04-29 20 views
8

Obecnie używam następującego zapytania, które trwa około 8 minut, aby zwrócić wynik ze względu na objętość danych (około 14 miesięcy). czy mogę to przyspieszyć?SQL - przyspieszenie zapytania

Baza w pytaniu MySQL z InnoDB silnik

select 
    CUSTOMER as CUST, 
    SUM(IF(PAGE_TYPE = 'C',PAGE_TYPE_COUNT,0)) AS TOTAL_C, 
    SUM(IF(PAGE_TYPE = 'D',PAGE_TYPE_COUNT,0)) AS TOTAL_D 
from 
     PAGE_HITS 
where 
    EVE_DATE >= '2016-01-01' and EVE_DATE <= '2016-01-05' 
    and SITE = 'P' 
    and SITE_SERV like 'serv1X%' 
group by 
    CUST 

danych jest podzielona przez 6 miesięcy. Każda kolumna, która trafia do klauzuli where, jest indeksowana. Tam całkiem sporo indeksów & będzie dużą listą do spisania tutaj. Stąd właśnie podsumowujące w słowach. W odniesieniu do tego zapytania, EVE_DATE + PAGE_TYPE_COUNT jest jednym z kompozytowych indeksów & więc są CUST + SITE_SERV + EVE_DATE, EVE_DATE + SITE_SERV, EVE_DATE + SITE,

Klucz podstawowy jest właściwie obojętne liczba automatycznego przyrostu. Nie jest uczciwy. Nie mam dostępu do planu wyjaśniającego. Zobaczę, co mogę w tej sprawie zrobić najlepiej.

Byłbym wdzięczny za pomoc w ulepszeniu tego.

+5

Czy możesz określić, które indeksy są używane (jeśli występują), a także jakie struktury wyglądają? Klucze główne używane itp.? – CR41G14

+2

możesz podać więcej szczegółów: liczba wierszy, indeksy, silnik magazynu itd. –

+0

Dziękuję bardzo. Niestety, przegapiłem aktualizację tych danych. Pozwól mi to teraz zrobić. – usert4jju7

Odpowiedz

2

Dobra, jako partycja zakres stół jest na EVE_DATE, DBMS powinien łatwo zobaczyć na której partycji do odczytu. Więc wszystko zależy od tego, jakiego indeksu użyć.

Istnieje jedna kolumna, którą sprawdzasz pod kątem równości (SITE = 'P'). Powinno to być pierwsze w twoim indeksie. Możesz wtedy dodać EVE_DATE iw dowolnej kolejności. Zatem twój indeks powinien być w stanie zlokalizować dane rekordy tabeli tak szybko jak to możliwe.

Jeśli jednak dodać inne pola wykorzystywanych w zapytaniu do indeksu w tabeli nawet nie trzeba czytać, ponieważ wszystkie dane będzie dostępna w indeksie samego:

create index on page_hits(site, eve_date, site_serv, customer, page_type, page_type_count); 

To powinien być optymalny indeks dla twojego zapytania, jeśli się nie mylę.

+0

Dziękuję stosy Thorsten. Ta ulepszona wydajność w pewnym stopniu. – usert4jju7

2

Głównym czynnikiem optymalizacji byłyby indeksy. Trzeba dopasować zapytanie tak ściśle, jak to możliwe, na przykład:

EVE_DATE, SITE, CUST, SITE_SERV 

Kolejność jest ważna, przynajmniej na SITE_SERV jako ostatniej wartości; gdy użyjesz na nim wartości LIKE, nie będziesz używał pełnej wartości, co pogorszy sprawność indeksów dla następnych kolumn.

Możesz również odrobinę zyskać, usuwając IF i zwracając typ i liczbę; może możesz przetworzyć/sformatować tę wartość w przedniej aplikacji?

W każdym razie powinieneś zacząć od profilowania bieżącego zapytania za pomocą EXPLAIN, aby zobaczyć, co idzie źle. Jeśli nie możesz, możesz spróbować odtworzyć strukturę, indeksy i kilka fałszywych danych w lokalnym DB, objętość jest tam nieistotna.

+0

Dziękuję, Preuk. Cieszę się, że mogę usunąć 'IF', w jaki sposób mogę wydajnie obliczyć warunkowe słowo" SUMA "? Czy mógłbyś pomóc tutaj? – usert4jju7

+0

Powiedziałbym, że wystarczy wybrać "PAGE_TYPE, SUMA (PAGE_TYPE_COUNT) AS TOTAL" i zarządzać przypadkiem "C" lub "D" w aplikacji frontendowej; ale jak mówię, prawdopodobnie nie jest to nawet tego warte. Poprawiono kilka literówek, moje zdanie nie miało żadnego sensu. – Preuk

+0

Dziękuję, Preuk. Użyję tej sugestii w innym miejscu mojego rozwoju. W odniesieniu do tego pytania, potrzebuję przetworzyć dane z warstwy DB :( – usert4jju7

3

Nie mam danych, więc nie mogę przetestować szybkości tego, ale myślę, że byłoby szybciej.

select 
    CUSTOMER as CUST, 
    SUM(PAGE_TYPE_COUNT * (PAGE_TYPE = 'C')) AS TOTAL_C, 
    SUM(PAGE_TYPE_COUNT * (PAGE_TYPE = 'D')) AS TOTAL_D 
from 
     PAGE_HITS 
where 
    EVE_DATE >= '2016-01-01' and EVE_DATE <= '2016-01-05' 
    and SITE = 'P' 
    and SITE_SERV like 'serv1X%' 
group by 
    CUST 

To działało dobrze na moim skrzypce na MySQL 5.6

+0

Dobra sztuczka, na pewno spróbuję tego, aby uprościć niektóre pytania, które mam; pod względem wydajności, czy masz jakieś dane? – Preuk

+0

Thankyou Xpy. To wygląda świetnie. Z pewnością skorzystam z tego gdzie indziej. W moim przypadku nie ma poprawy. Jest to naprawdę dobry – usert4jju7

2

Dodaj te dwa indeksy:

INDEX(site, date) 
INDEX(site, site_serv) 

optymalizator będzie spojrzeć na statystyki i wybrać między nimi. Z grubsza rzecz biorąc, pierwszy byłby lepszy, gdyby było mniej wierszy z "P" & DATE w tym zakresie, niż "P" & "serv1X%".

Tak, wskaźnik "pokrycia", że Thorsten może być lepszy, ale ma więcej pól niż chciałbym umieścić w indeksie.

PARTITIONingmoże pomoc. Ale jest zbyt mało informacji, które można by na pewno powiedzieć. Przyczyną podziału na partycje może być dwuwymiarowe wyszukiwanie - zakres dat i "serv1X%". Będziesz musiał podzielić partycję na datę lub site_serv, a następnie mieć PRIMARY KEY(site, ..., ...) z drugą (date lub site_serv) jako drugą kolumną. Pozostałe kolumny powinny zawierać zarówno klucz partycji, jak i pewną kolumnę, aby była unikatowa. To jest tak brudne, że nie chcę tego przemyśleć.

+0

Dziękuję Rick. Pomogło to poprawić wydajność. – usert4jju7