MySQL: utwórz indeks na 1,4 miliarda rekordów

9

Mam tabelę z 1,4 miliarda rekordów. Struktura tabeli jest następująca:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

Wymagane jest utworzenie indeksu nad kolumną text.

Rozmiar stołu wynosi około 34G.

Próbowałem utworzyć indeks za pomocą następującej instrukcji:

ALTER TABLE text_page ADD KEY ix_text (text)

Po 10 godzinach oczekiwania w końcu zrezygnowałem z tego podejścia.

Czy istnieje jakieś realne rozwiązanie tego problemu?

AKTUALIZACJA : jest mało prawdopodobne, że tabela zostanie zaktualizowana, wstawiona lub usunięta. Powodem, dla którego należy utworzyć indeks w kolumnie, textjest to, że tego rodzaju zapytania SQL byłyby często wykonywane:

SELECT page_id FROM text_page WHERE text = ?

AKTUALIZACJA : Rozwiązałem problem, dzieląc tabelę na partycje.

Stół jest podzielony na 40 części na kolumnie text. Następnie utworzenie indeksu na stole zajmuje około 1 godziny.

Wydaje się, że tworzenie indeksu MySQL staje się bardzo wolne, gdy rozmiar tabeli staje się bardzo duży. Partycjonowanie zmniejsza tabelę na mniejsze pnie.

SiLent SoNG
źródło
1
Co jest złego w używaniu zwykłego CREATE INDEXstwierdzenia?
Sugerowałbym, że lepiej odpowiedzieć na to pytanie w ServerFault - jest to bardziej administrator DB niż pytanie programistyczne.
odtąd
@Derk: normalne podejście CREATE INDEX jest zbyt wolne. Muszę wykonać zadanie w ciągu 1 dnia.
1
Hmm ... Nie sądzę, że da się to obejść. Budowanie indeksu wymaga, aby DBMS skanował wszystkie rekordy, zbierał ich pola „tekstowe” i wstawiał / zmieniał odpowiednie węzły / poddrzewa. A to zajmuje dużo czasu dla 34G ...
chiccodoro
Ile pamięci ma Twój serwer DB? Czy skonfigurowałeś MySQL do korzystania z całej tej pamięci, czy też sam się ogranicza?

Odpowiedzi:

4

Czy to możliwe, że Twój system po prostu nie spełnia tego zadania? Nie używam MySQL (tutaj SQL Server), ale znam ból związany z indeksowaniem 800 milionów wpisów. Zasadniczo ... potrzebujesz do tego odpowiedniego sprzętu (jak w: wiele szybkich dysków). Używam teraz prawie tuzina Velociraptorów, a wydajność jest świetna;)

Serwery SQL (nie jako MS SQL Server, ale jako serwery baz danych używające SQL) żyją i umierają z dostępem do dysku, a normalne dyski po prostu nie są w stanie wykonać większych operacji.

TomTom
źródło
Wątpię, czy tworzenie indeksu jest zwykle bardzo szybkie, jeśli liczba rekordów jest niewielka; powiedzmy miliony. Ale gdy liczba ta wynosi miliardy, tworzenie indeksu staje się tak wolne. Wydaje się, że wzrost czasu ma charakter wykładniczy.
Nie powinno tak być. Ogólnie MySQL ma ograniczenia, ale nie jest to beznadziejna baza danych i byłoby to BARDZO złe. Generowanie indeksu działa wolniej, ale według log (n), a nie (n), więc tak naprawdę nie powinno być tak źle.
TomTom,
4

Możesz utworzyć indeks dla pierwszych (na przykład 10) znaków w polu tekstowym.

Z Dokumentów:

Można tworzyć indeksy, które wykorzystują tylko wiodącą część wartości kolumn, używając składni nazwa_kolumny (długość) do określenia długości prefiksu indeksu:

CREATE INDEX ix_text ON text_page (text(10))

źródło
4

Rozwiązałem problem, dzieląc tabelę.

Stół jest podzielony na 40 części na kolumnie text. Następnie utworzenie indeksu na stole zajmuje około 1 godziny.

Wydaje się, że tworzenie indeksu MySQL staje się bardzo wolne, gdy rozmiar tabeli staje się bardzo duży. Partycjonowanie zmniejsza tabelę na mniejsze pnie.

SiLent SoNG
źródło
Czyli 40 x 1 godzina to mniej niż 10 godzin?
symcbean
3

Ustaw sort_buffer_size na 4 GB (lub tyle, ile możesz, w zależności od ilości dostępnej pamięci).

W tej chwili indeks tworzenia wykonuje sortowanie, ale ponieważ masz 32 MB sort_buffer_size, to w zasadzie niepotrzebnie wyrzuca dysk twardy.

Tster
źródło
Te posty nie zgadzają się z tobą bezpośrednio: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size i lepiej ronaldbradford.com/blog/… Wygląda na to, że to nie jest globalna wartość, to jest na zapytanie, więc to 4 GB na każde zapytanie, które polecasz. Ponadto, gdy przekroczy 256 KB, zostaje zamapowany na pamięć zamiast na rzeczywistą pamięć w pamięci. Utrzymanie go na małym poziomie wymaga wielu przejść, ale unika dysku (nie zamienia się).
Ry4an Brase
3

Jeśli nie musisz wykonywać takich zapytań jak:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Sugerowałbym utworzenie nowej kolumny mieszającej i indeksowanie tabeli według kolumny. Całkowity rozmiar tabeli + indeksu może być znacznie mniejszy.

UPD : Nawiasem mówiąc, 1,4 miliarda liczb całkowitych klucza podstawowego zajmuje około 6 GB, co oznacza, że ​​średnia długość łańcucha jest mniejsza niż 30 znaków, więc indeksowanie na prefiksie może być bardziej korzystne.

Powinieneś także spojrzeć na silnik pamięci masowej MERGE .

Newtover
źródło
2

Jednym ze sposobów jest utworzenie nowej tabeli z zestawem indeksów i skopiowanie danych do nowej tabeli.

Upewnij się także, że masz wystarczającą ilość miejsca na temp.

dekompilowany
źródło
1
Próbowałem tego podejścia. Po 10 godzinach mniej niż 1% danych zostało skopiowanych do nowej tabeli.
1
Stary ... to 1,4 miliarda rekordów. Nie milion, MILIONÓW. To dużo. To zajmie trochę czasu.
Jeśli wybierzesz tę metodę, podziel kopię na mniejsze części. Powiedz około 100 do 200 milionów na każdą kopię.
1
@ dekompilacja, rozbicie go na mniejsze fragmenty nic nie da (właściwie może sprawić, że będzie mniej wydajne). @Bryan, nawet przy 1,4 miliarda rekordów nie powinno to zająć 1000 godzin.
0

Jeśli nadal zastanawiasz się, jak to zrobić najlepiej, sugeruję skorzystanie z internetowego narzędzia do zmiany tabeli.

W Internecie jest ich wiele, jedną ze znanych jest:

Mamy te same problemy z dużymi tabelami (ponad 500 mil rekordów) i przeróbka przebiega idealnie. Tworzy nową tabelę tmp, dodaje wyzwalacz do oryginalnej tabeli (dla nowych aktualizacji / usuwania / wstawiania rekordów), a tymczasem kopiuje wszystkie rekordy do nowej tabeli (z nową strukturą)

Powodzenia!

Ali Alwash
źródło