10

Obecnie próbuję poprawić szybkość SELECTS dla tabeli MySQL i docenił wszelkie sugestie na temat sposobów poprawy.Mysql popraw prędkość SELECT

Mamy ponad 300 milionów rekordów w tabeli, a tabela ma znacznik struktury, datę, wartość. Klucz podstawowy to połączony klucz tagu i daty. Tabela zawiera informacje dla około 600 unikalnych tagów, które zawierają średnio około 400 000 wierszy, ale mogą zawierać się w przedziale od 2000 do ponad 11 milionów wierszy.

Zapytania prowadzone przeciwko tabeli są:

SELECT date, 
     value 
    FROM table 
    WHERE tag = "a" 
    AND date BETWEEN 'x' and 'y' 
ORDER BY date 

.... i istnieje bardzo niewiele, jeśli żadnych płytek.

Próbowałem partycjonować dane przez znacznik na różną liczbę partycji, ale wydaje się, że ma niewielki wzrost prędkości.

+0

Po pominięciu opcji "ZAMÓWIENIE PRZEZ", czy to pomaga? Czy możesz publikować rzeczywiste terminy zapytań zi bez ORDER BY? –

+5

opublikować wyjaśnienie zapytania wykonując EXPLAIN SELECT data, wartość Z tabeli gdzie tag = "a" i data MIĘDZY "x" i "y" według daty – piyush

+3

Nie wspomniano o indeksach - spróbuj jedną w kolumnie (tag, data, wartość) lub pojedynczy indeks złożony zawierający wszystkie trzy. Pamiętaj, że kolejność kolumn ma znaczenie w złożonym indeksie - począwszy od lewej, jeśli kolumna nie jest przywoływana w zapytaniu, indeks nie będzie używany. –

Odpowiedz

4

trochę czasu, aby przeczytać moją odpowiedź tutaj: (ma podobne ilości Twoi)

500 milionów wierszy, 15 mln zakres wierszy skanowanie w 0,02 sekundy.

MySQL and NoSQL: Help me to choose the right one

następnie zmienić silnik stół do InnoDB następująco:

create table tag_date_value 
(
tag_id smallint unsigned not null, -- i prefer ints to chars 
tag_date datetime not null, -- can we make this date vs datetime ? 
value int unsigned not null default 0, -- or whatever datatype you require 
primary key (tag_id, tag_date) -- clustered composite PK 
) 
engine=innodb; 

można rozważyć następujące jako klucz podstawowy Zamiast:

primary key (tag_id, tag_date, value) -- added value save some I/O 

ale tylko wtedy, gdy wartość isnt niektóre DUŻY typ varchar!

zapytania jak poprzednio:

select 
tag_date, 
value 
from 
tag_date_value 
where 
tag_id = 1 and 
tag_date between 'x' and 'y' 
order by 
tag_date; 

nadziei, że to pomoże :)

EDIT

oh zapomniałem wspomnieć - wykorzystanie Dont alter table zmienić typ silnika od mysiam do InnoDB ale raczej zrzuć dane do plików csv i ponownie zaimportuj do nowo utworzonej i pustej tabeli innodb.

Uwaga Zamawiam dane podczas procesu eksportu - indeksy klastrowe to KLUCZ!

Export

select * into outfile 'tag_dat_value_001.dat' 
fields terminated by '|' optionally enclosed by '"' 
lines terminated by '\r\n' 
from 
tag_date_value 
where 
tag_id between 1 and 50 
order by 
tag_id, tag_date; 

select * into outfile 'tag_dat_value_002.dat' 
fields terminated by '|' optionally enclosed by '"' 
lines terminated by '\r\n' 
from 
tag_date_value 
where 
tag_id between 51 and 100 
order by 
tag_id, tag_date; 

-- etc... 

importu

import z powrotem do tabeli w odpowiedniej kolejności!

start transaction; 

load data infile 'tag_dat_value_001.dat' 
into table tag_date_value 
fields terminated by '|' optionally enclosed by '"' 
lines terminated by '\r\n' 
(
tag_id, 
tag_date, 
value 
); 

commit; 

-- etc... 
0

Powiedziałbym, że jedyną szansą na dalszą poprawę jest indeks obejmujący wszystkie trzy kolumny (znacznik, dane, wartość). Dzięki temu unika się dostępu do stołu.

Nie sądzę, że partycjonowanie może w tym pomóc.

0

Przypuszczam, że dodanie indeksu na (tag, date) pomogłoby:

alter table table add index (tag, date); 

proszę pisać wynikiem wyjaśnić na tej kwerendy (wyjaśnij wybrać datę, wartość z ......)

+0

Deklaracja klucza podstawowego utworzy ten indeks. –

+0

prawdopodobnie myisam, a tym samym nie klastrowany indeks PKT - eeek –

0

Myślę, że kolumna value jest na dole problemów z wydajnością. Nie jest częścią indeksu, więc będziemy mieć dostęp do stołu. Ponadto uważam, że ORDER BY prawdopodobnie nie wpłynie znacząco na wydajność, ponieważ jest częścią indeksu i należy go zamówić.

Będę argumentował moje podejrzenia co do kolumny value przez fakt, że partycja tak naprawdę nie skraca czasu wykonania zapytania. Czy możesz wykonać kwerendę bez numeru value i podać nam wyniki, a także EXPLAIN? Czy naprawdę potrzebujesz tego dla każdego wiersza i jakiego rodzaju jest to kolumna?

Pozdrawiam!

+0

Wartość jest VARCHAR i jest potrzebna dla każdego zapytania. Wysłałem EXPLAIN powyżej ... – allyLogan

+0

Więc nadal wydaje się, że to jest problem. Co się stanie, jeśli uruchomisz kwerendę bez wartości do testu? Czy wzrost jest znaczący? –

1

Co to jest liczność pola daty (czyli ile różnych wartości pojawia się w tym polu)? Jeśli data MIĘDZY "x" I "y" jest bardziej ograniczona niż tag = "a" częścią klauzuli WHERE, spróbuj wprowadzić klucz podstawowy (data, tag) zamiast (tag, date), pozwalając na użycie daty jako wartość indeksowana.

Należy również zachować ostrożność przy określaniu "x" i "y" w klauzuli WHERE. Istnieją pewne okoliczności, w których MySQL będzie rzutować każde pole daty, aby pasowało do nie-daty typu sugerowanych wartości.

+0

Istnieje o wiele więcej różnych wartości dla kolumny daty niż kolumna znacznika, ponieważ kolumna z datą może mieć wartość co kilka sekund i nie jest przewidywalna, a kolumna znacznika ma tylko 600 różnych wartości. – allyLogan

+0

W zależności od tego, jak szeroki jest twój x do y Zakres dat to, że możesz uzyskać znacznie lepszą wydajność, próbując (data, tag) jako klucz podstawowy. Spróbuj. –

+0

podczas gdy nazywamy datę "datą", w rzeczywistości jest to znacznik czasu z wartościami co sekundę, a niektóre znaczniki mają 11 milionów wartości, więc zakres dat jest dość szeroki. Próbowałem utworzyć nową tabelę z (datą, znacznikiem) jako kluczem podstawowym, ale po około 12 godzinach przesyłania danych było to tylko 6-ty etap! – allyLogan

0

Spróbuj wstawić tylko potrzebne daty do tabeli tymczasowej, a na koniec wybierz z tabeli tymczasowej dla tagów i porządku.

CREATE temporary table foo 
SELECT date, value 
FROM table 
WHERE date BETWEEN 'x' and 'y' ; 

ALTER TABLE foo ADD INDEX index(tag); 

SELECT date, value 
FROM foo 
WHERE tag = "a" 
ORDER BY date; 

jeśli to nie działa, spróbuj zamiast tego utworzyć foo z zaznaczonego znacznika.

CREATE temporary table foo 
SELECT date, value 
FROM table 
WHERE tag = "a";  

ALTER TABLE foo ADD INDEX index(date); 

SELECT date, value 
FROM foo 
WHERE date BETWEEN 'x' and 'y' 
ORDER BY date; 
1

Chciałbym zrobić dwie rzeczy - po pierwsze rzucać kilka indeksów tam około tagu i datą jak zasugerowano powyżej:

alter table table add index (tag, date); 

Następny złamać zapytanie do głównego zapytania i sub-select, w którym jesteś zawężenie wyników w dół, gdy pojawi się w głównym zapytaniu:

SELECT date, value 
FROM table 
WHERE date BETWEEN 'x' and 'y' 
AND tag IN (SELECT tag FROM table WHERE tag = 'a') 
ORDER BY date 
1

zapytanie prosi o kilka rzeczy - iz tym wysoką liczbę wierszy, wygląd danych może zmienić to, co najlepsze podejście jest.

SELECT date, value 
    FROM table 
    WHERE tag = "a" 
    AND date BETWEEN 'x' and 'y' 
    ORDER BY date 

Jest kilka rzeczy, które mogą spowolnić to wybrane zapytanie.

  1. Bardzo duży zestaw wyników, który należy posortować (uporządkować według).
  2. Bardzo duży zestaw wyników. Jeśli znacznik i data znajdują się w indeksie (i załóżmy, że jest tak dobry, jak to tylko możliwe), każdy wiersz wyniku będzie musiał opuścić indeks, aby wyszukać pole wartości. Pomyśl o tym, jakby potrzebować pierwszego zdania każdego rozdziału książki. Jeśli potrzebujesz tylko znać nazwy rozdziałów, łatwo - możesz je pobrać ze spisu treści, ale ponieważ potrzebujesz pierwszego zdania, musisz przejść do właściwego rozdziału. W niektórych przypadkach optymalizator może wybrać tylko przeglądanie całej książki (skanowanie tabeli w języku zapytań do planu zapytania), aby uzyskać te pierwsze zdania.
  3. Filtrowanie według niewłaściwej w punkcie pierwszym. Jeśli indeks znajduje się w znaczniku zamówienia, date ... wtedy tag powinien (dla większości twoich zapytań) być bardziej rygorystyczny z dwóch kolumn. Zasadniczo, chyba że masz więcej tagów niż dat (lub może dat w typowym zakresie dat), daty powinny być pierwszą z dwóch kolumn w indeksie.

Kilka zaleceń:

  1. Zastanów się, czy to możliwe, aby obciąć niektóre z tych danych, jeśli jest zbyt stary, aby dbać o większość czasu.
  2. Spróbuj odtwarzać za pomocą bieżącego indeksu - tj. Zmień kolejność pozycji w nim.
  3. Pozbądź się bieżącego indeksu i zastąp go indeksem pokrywającym (zawiera wszystkie 3 pola).
  4. Uruchom EXPLAIN i upewnij się, że w ogóle korzysta z Twojego indeksu.
  5. Przejdź do innego magazynu danych (mongo db?) Lub w inny sposób upewnij się, że ta tabela potworów jest przechowywana w pamięci w jak największym stopniu.