Jakie są powody ** NIE ** używania silnika pamięci MEMORY w MySQL?

28

Niedawno odkryłem, że MySQL ma silnik „pamięci”, o którym nie wiedziałem (większość mojej pracy z bazami danych dotyczy projektów hobbystycznych, więc uczę się tego, czego potrzebuję). Wygląda na to, że ta opcja powinna dać mi znacznie lepszą wydajność, więc zastanawiam się, czy są jakieś wady z tym związane. Dwa, które znam to:

  1. Potrzebuję wystarczającej ilości pamięci RAM, aby pomieścić dane stoliki.
  2. Tabele zostaną utracone, jeśli urządzenie się wyłączy.

Uważam, że nr 1 nie powinien stanowić problemu, ponieważ używam AWS EC2 i mogę w razie potrzeby przejść do typu instancji z większą pamięcią. Myślę, że mogę złagodzić # 2, w razie potrzeby zrzucając z powrotem na dysk.

Jakie są inne problemy? Czy silnik pamięci może kiedykolwiek dać gorszą wydajność niż MyISAM lub InnoDB? Myślę, że czytam coś, co różni się indeksami w tym silniku; czy muszę się tym martwić?

Michael McGowan
źródło

Odpowiedzi:

27

Patrząc na listę dostępności funkcji na stronie http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html wyskakują dwa możliwe problemy:

  1. Nie była wymagana żadna obsługa transakcji ani FK, co oznacza, że ​​będziesz musiał zarządzać integralnością transakcji i integralności referencyjnej we własnym kodzie (co może okazać się o wiele mniej wydajne niż pozwolenie DB na wykonanie tego za Ciebie, chociaż to bardzo zależy od aplikacji) oczekiwane wzorce zachowań).
  2. Tylko blokowanie na poziomie tabeli: może to być znacząca bariera dla skalowalności, jeśli aplikacja potrzebuje wielu współbieżnych programów zapisujących do tego samego zestawu tabel lub w przypadkach, w których operacje odczytu używają blokad, aby zapewnić spójność danych - w takich przypadkach tabela oparta na dyskach obsługuje znacznie drobniejszą ziarnistość blokady, będzie działać znacznie lepiej, jeśli wystarczająca ilość jej zawartości jest obecnie buforowana w pamięci RAM.

Poza tym, zakładając, że masz wystarczającą ilość pamięci RAM, tabela oparta na pamięci powinna być szybsza niż tabela oparta na dysku. Oczywiście należy wziąć pod uwagę migawki na dysk, aby rozwiązać problem tego, co dzieje się po zresetowaniu instancji serwera, co może całkowicie zignorować ogólną korzyść z wydajności, jeśli dane często wymagają przechwytywania (jeśli możesz żyć z utratą dnia dane w takim przypadku można wykonać kopię zapasową raz dziennie, ale w większości przypadków byłoby to nie do przyjęcia).

Alternatywą może być:

  1. Używaj tabel opartych na dyskach, ale upewnij się, że masz więcej niż wystarczającą ilość pamięci RAM, aby pomieścić je wszystkie w pamięci RAM w danym momencie (a „wystarczająca ilość pamięci RAM” może być większa niż myślisz, ponieważ musisz uwzględnić wszelkie inne procesy na komputerze, system operacyjny Bufory IO / pamięć podręczna i tak dalej)
  2. Skanuj całą zawartość (wszystkie strony danych i indeksów) tabeli przy każdym uruchomieniu, aby wstępnie załadować zawartość do pamięci SELECT * FROM <table> ORDER BY <pkey fields>dla każdej tabeli, a następnie SELECT <indexed fields> FROM <table> ORDER BY <index fields>dla każdego indeksu

W ten sposób wszystkie twoje dane są w pamięci RAM, musisz tylko martwić się o wydajność I / O dla operacji zapisu. Jeśli wspólny zestaw roboczy aplikacji jest znacznie mniejszy niż cała baza danych (co zwykle ma miejsce - w większości aplikacji większość użytkowników będzie przeglądać najnowsze dane tylko wtedy, gdy jest to czas), lepiej być bardziej selektywnym w kwestii tego, ile skanujesz w celu wstępnego załadowania do pamięci, umożliwiając załadowanie reszty z dysku na żądanie.

David Spillett
źródło
Dlaczego potrzebujesz integralności transakcyjnej dla bazy danych w pamięci? Jeśli moc zniknie, i tak wszystko stracisz.
osa
@osa: zakładając, że pozwala to na równoczesny dostęp zamiast szeregowania wszystkiego, będziesz potrzebować do tego jakiejś formy zarządzania integralnością.
David Spillett,
14

Istnieje wiele przypadków, w których nie należy używać silnika pamięci - i kiedy InnoDB będzie szybszy. Musisz tylko pomyśleć o współbieżności, a nie trywialnych testach jednowątkowych.

Jeśli masz wystarczająco dużą pulę buforów, InnoDB stanie się również rezydentem pamięci dla operacji odczytu. Bazy danych mają pamięci podręczne . Rozgrzewają się!

Ponadto - nie lekceważ wartości blokowania na poziomie wiersza i MVCC (czytniki nie blokują programów zapisujących ). Może być „wolniejszy”, gdy zapis musi trwać na dysku. Ale przynajmniej nie będziesz blokował podczas tej operacji zapisu, tak jakbyś był na tablicy pamięci (bez MVCC; blokowanie na poziomie tabeli).

Morgan Tocker
źródło
3

Dla przypomnienia. Testowałem tabele MySQL w pamięci, aby przechowywać pewne informacje. I przetestowałem APC (APCu) PHP pod kątem przechowywania tych samych informacji.

Dla 58000 rejestrów. (varchar + liczba całkowita + data).

  1. Informacje oryginalne 24 MB w formacie tekstowym (format csv).
  2. APC PHP zużywa 44,7 MB pamięci RAM.
  3. Tabela MySQL wykorzystuje 575 MB pamięci RAM.

Tabela ma tylko jeden indeks, więc nie sądzę, że jest to główny czynnik.

Wniosek:

Tabela pamięci nie jest opcją dla „dużych” tabel, ponieważ zużywa zbyt dużo pamięci.

magallanes
źródło
2
To jest uproszczona odpowiedź. Mechanizm pamięci MEMORY można dostroić, używając mniejszych typów danych, jawnie definiując BTREE jako typ indeksu i ograniczając ilość danych ładowanych do pamięci RAM. Jest to nadal opłacalna opcja dla mniejszych zestawów. Istnieją również inne czynniki, takie jak agresywne dyskowe operacje we / wy. Zobacz moje posty dba.stackexchange.com/questions/6156/… i dba.stackexchange.com/questions/2868/… )
RolandoMySQLDBA
W rzeczywistości sprawdziłem zmianę indeksu (a nawet całkowite usunięcie go), a rozmiar nie zmienił się tak bardzo (w tym rekonstrukcja tabeli od zera). IMHO Mysql robi coś pod maską, może to być jakaś optymalizacja lub przydzielanie największego rozmiaru na kolumnę (np. W varchar).
magallanes
6
Przyczyną jest prawie na pewno twój VARCHAR: "MEMORY tables use a fixed-length row-storage format. Variable-length types such as VARCHAR are stored using a fixed length." dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html Skutecznie wydaje się, że VARCHAR staje się CHAR dzięki silnikowi MEMORY.
Matthew1471,
2

Inną wadą tabel opartych na MEMORY jest to, że nie można ich wielokrotnie odwoływać w tym samym zapytaniu. Przynajmniej takie zachowanie znaleziono do wersji 5.4. Jak w przypadku CTE (od wersji 8.x) nie ma potrzeby używania tabel pośrednich opartych na memie w przypadku skomplikowanych procedur.

Kondybas
źródło
1

Według instrukcji MySQL i MariaDB BLOB i CLOB (różne typy TEKSTÓW) nie są obsługiwane przez pamięć MEMORY. Dla naszych własnych celów uczyniło to silnik pamięci MEMORY prawie bezużytecznym.

http://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html

Tabele MEMORY nie mogą zawierać kolumn BLOB ani TEXT.

https://mariadb.com/kb/en/mariadb/memory-storage-engine/

W tabelach MEMORY można stosować typy o zmiennej długości, takie jak VARCHAR. Kolumny BLOB lub TEXT nie są obsługiwane dla tabel MEMORY.

Próbując przekonwertować tylko część bazy danych na pamięć MEMORY, stwierdziłem, że klucze obce silnika między pamięcią masową nie są obsługiwane. Tak więc wszystkie tabele, które powinny zawierać odwołania do kluczy obcych do tabel zawierających BLOB / CLOB, powinny również znajdować się w typach pamięci innych niż pamięć (przynajmniej wpływa to na tabele podrzędne InnoDB).

użytkownik2134886
źródło
1

Tabele MEMORY nie są przeznaczone do trwałego przechowywania, w szczególności dużych podzbiorów danych lub czegokolwiek, w którym zachowanie jest krytyczne. Z mojego doświadczenia ich najlepszym celem jest przechowywanie przejściowych rekordów podczas tworzenia i wypełniania tabel tymczasowych podczas złożonych procedur, które działają znacznie szybciej niż większość innych typów tabel do tego celu, pod warunkiem, że próg bufora kluczowego dla silnika jest wystarczająco wysoki, aby nie ponieść zapis na dysku. W tym celu może to działać o rząd wielkości szybciej niż MyISAM lub InnoDB, ponieważ nie ma dyskowego wejścia / wyjścia, aw przypadku tabeli, która jest zawarta w określonej procedurze, indeksowanie i relacje nie mają tak dużego znaczenia, jak byłoby tam, gdzie oczekuje się wytrwałości.

mopsyd
źródło
1

Oprócz poprzednich odpowiedzi. prosto z podręcznika MySQL 5.7:

„Wydajność PAMIĘCI jest ograniczona rywalizacją wynikającą z wykonywania jednowątkowego i narzutu blokady tabeli podczas przetwarzania aktualizacji. Ogranicza to skalowalność, gdy zwiększa się obciążenie, szczególnie w przypadku zestawień instrukcji zawierających zapisy”.

... i to jest bardzo realne ograniczenie. Na przykład: gdy masz wiele sesji próbujących stworzyć ładne, szybkie tabele tymczasowe MEMORY, jednowątkowe może powodować poważne wąskie gardło wydajności.

Eljuan
źródło