MyISAM kontra InnoDB [zamknięte]


857

Pracuję nad projektami, które wymagają dużo zapisów do bazy danych, powiedziałbym ( 70% wstawek i 30% odczytów ). Ten stosunek obejmuje także aktualizacje, które uważam za jeden odczyt i jeden zapis. Odczyty mogą być brudne (np. Nie potrzebuję 100% dokładnych informacji w momencie odczytu).
Zadanie, o którym mowa, będzie wykonywać ponad milion transakcji na bazie danych na godzinę.

Przeczytałem wiele rzeczy w Internecie na temat różnic między MyISAM a InnoDB, a MyISAM wydaje mi się oczywistym wyborem dla konkretnej bazy danych / tabel, których będę używać do tego zadania. Z tego, co wydaje mi się czytać, InnoDB jest dobry, jeśli transakcje są potrzebne, ponieważ obsługiwane jest blokowanie na poziomie wiersza.

Czy ktoś ma jakieś doświadczenie z tego typu obciążeniem (lub wyższym)? Czy MyISAM jest właściwą drogą?


13
MySQL Wydajność Blog jest doskonałym źródłem informacji dla tego typu rzeczy.
ceejayoz

3
Zależy to nieco od tego, czy Twój system jest zorientowany na OLTP, czy bardziej na bazę danych (gdzie większość zapisów jest ładowana zbiorczo).
nos

35
MyISAM nie obsługuje blokowania wierszy, transakcji, nie obsługuje nawet kluczy obcych ... cholera, ponieważ nie może zapewnić ACID , trudno nawet uznać go za właściwą bazę danych! To dlatego InnoDB jest domyślnym silnikiem od MySQL 5.5 ... ale z jakiegokolwiek powodu MyISAM nadal jest domyślnym silnikiem dla tabel tworzonych w PhpMyAdmin, więc wiele amatorskich baz danych działa od MyISAM.
BlueRaja - Danny Pflughoeft


Odpowiedzi:


523

Krótko omówiłem to pytanie w tabeli, abyś mógł stwierdzić, czy wybrać InnoDB czy MyISAM .

Oto krótki przegląd silnika bazy danych db, którego należy użyć w danej sytuacji:

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
Wymagane wyszukiwanie pełnotekstowe Tak 5.6.4
-------------------------------------------------- --------------
Wymagaj transakcji Tak
-------------------------------------------------- --------------
Często wybierane zapytania Tak      
-------------------------------------------------- --------------
Częste wstawianie, aktualizacja, usuwanie Tak
-------------------------------------------------- --------------
Blokowanie wierszy (przetwarzanie wielu na jednym stole) Tak
-------------------------------------------------- --------------
Relacyjny projekt bazy Tak

Podsumowanie

  • W prawie wszystkich okolicznościach najlepszym rozwiązaniem jest InnoDB
  • Ale częste czytanie, prawie brak pisania, używaj MyISAM
  • Wyszukiwanie pełnotekstowe w MySQL <= 5.5, użyj MyISAM

11
InnoDB ma indeksy pełnotekstowe w MySQL 5.6, ale jak dotąd nie są tak naprawdę gotowe do użytku produkcyjnego.
Bill Karwin

3
Zgodny z 12.9. Funkcje wyszukiwania pełnotekstowego, „Indeksów pełnotekstowych można używać tylko z tabelami InnoDB lub MyISAM”. Wydaje się OK dla MySQL> = 5.6, jednak ta sama strona dla MySQL 5.5, wciąż mówi: „Indeksów pełnotekstowych można używać tylko z tabelami MyISAM”. Powyższą tabelę można zaktualizować, aby pokazać, jak różni się ona od wersji MySQL. Niestety, jak dotąd MySQL 5.5 wydaje się być standardem.
Hibou57

2
Co to znaczy: InnoDB - full-text: 5.6.4?? Jest tak czy nie?

2
MyISAM przechowuje również wewnętrznie liczbę wierszy. Dlatego funkcja Count () jest prawie bezpłatna w MyISAM, natomiast w InnoDB zajmuje zauważalnie dużo czasu.
Hedeshy,

3
dobry stół, ale dodanie wiersza dla jakości i stabilności, MyIsam = nie, innoDB = tak sprawiłoby, że byłoby jeszcze lepiej
pilavdzice

268

Nie jestem ekspertem od baz danych i nie mówię z doświadczenia. Jednak:

Tabele MyISAM używają blokowania na poziomie tabeli . Na podstawie prognoz ruchu masz prawie 200 zapisów na sekundę. Dzięki MyISAM tylko jeden z nich mógł być w toku . Musisz upewnić się, że Twój sprzęt może nadążyć za tymi transakcjami, aby uniknąć przekroczenia, tj. Pojedyncze zapytanie nie może zająć więcej niż 5 ms.

To sugeruje, że potrzebujesz silnika pamięci, który obsługuje blokowanie na poziomie wiersza, tj. InnoDB.

Z drugiej strony napisanie kilku prostych skryptów do symulacji obciążenia za pomocą każdego silnika pamięci powinno być dość trywialne, a następnie porównanie wyników.


12
Blisko 200? Jeśli jego średnia transakcja powoduje 2,5 zapytań, jest to [(2,5 * 1M) / 3600s =] bliżej 700.
Ozzy

12
Nie zgadzam się również z tym, a single query can take no more than 5msże przyjęliście 2 nieprawdopodobne założenia; Odp .: Wszystkie zapytania wymagały tej samej tabeli & B: dostępne było tylko 1 połączenie! Powinienem poinformować, że konfiguracja Linux i MySQL 5.5 z wysoką pamięcią RAM może obsługiwać aż 10 000 jednoczesnych połączeń (patrz: dev.mysql.com/doc/refman//5.5/en/too-many-connections.html )
Ozzy

152
Gdy tabela jest zablokowana, tylko jedno zapytanie może być uruchomione przeciwko niej jednocześnie. Nie ma znaczenia, czy serwer obsługuje 10000 równoczesnych połączeń, każde utworzy kopię zapasową, gdy tabela jest zablokowana.
Ryaner,

2
Warto również wiedzieć, że MyISAM obsługuje indeks przestrzenny, podczas gdy InnoDB nie. MyISAM nie wydaje się używać kluczy obcych, chociaż nie uniemożliwia to ich utworzenia.
kriver

4
@kriver: Nie możesz mieć obcych kluczy w tabelach MyISAM. Możesz dołączyć definicje FK do instrukcji CREATE TABLE, ale one (definicje) są po prostu ignorowane.
ypercubeᵀᴹ

191

Ludzie często mówią o wydajności, odczytach i zapisach, kluczach obcych itp., Ale moim zdaniem jest jeszcze jedna niezbędna funkcja silnika pamięci masowej: aktualizacje atomowe.

Spróbuj tego:

  1. Wystaw aktualizację na stole MyISAM, która zajmuje 5 sekund.
  2. W trakcie aktualizacji, powiedzmy 2,5 sekundy, naciśnij Ctrl-C, aby ją przerwać.
  3. Obserwuj efekty na stole. Ile wierszy zostało zaktualizowanych? Ile nie zostało zaktualizowanych? Czy tabela jest nawet czytelna, czy też została uszkodzona po naciśnięciu Ctrl-C?
  4. Wypróbuj ten sam eksperyment z UPDATE na tabeli InnoDB, przerywając trwające zapytanie.
  5. Obserwuj tabelę InnoDB. Zerowane wiersze zostały zaktualizowane. InnoDB zapewnił, że masz aktualizacje atomowe, a jeśli nie można zatwierdzić pełnej aktualizacji, wycofuje całą zmianę. Ponadto tabela nie jest uszkodzona. Działa to nawet w przypadku killall -9 mysqldsymulacji awarii.

Wydajność jest oczywiście pożądana, ale nie utrata danych powinna ją pokonać.


4
Dla przypomnienia, MyISAM nie obsługuje również innych cech bazy danych ACID - spójności, izolacji i trwałości.
Bill Karwin,

Control-C nie powinien uszkodzić tabeli - tak jak w TABELI SPRAWDŹ TABELĘ zwróci sukces i wszystkie zapytania będą przebiegać bez błędów. MyISAM przerwie aktualizację bez aktualizacji wszystkich rekordów, ale tabela zachowa wewnętrzną integralność strukturalną. Zabicie mysqlda za pomocą SIGTERM będzie miało ten sam efekt. Jeśli jednak podasz mu SIGKILL (zabij -9) lub jakiś sygnał awarii (lub sam go zdobędzie, gdy trafi na błąd), lub jeśli system ulegnie awarii / utracie zasilania, to będzie inna historia - możesz zobaczyć Korupcja na poziomie MyISAM.
Sasha Pachev

1
InnoDB może również sam się zepsuć po królewsku, zwykle bardziej po królewsku niż MyISAM. Ironią ACID jest to, że mamy pojęcie wszystkiego lub nic. Kiedy więc InnoDB nie może dać wszystkiego, nie daje nic - wewnętrzne twierdzenie i w ogóle odmawia uruchomienia, ponieważ jeden bajt w jakiejś strukturze jest nieprawidłowy - 90% czasu można było zignorować i co najwyżej wpłynęłoby tylko na jedną tabelę. Najnowsze serwery Percona mają opcję radzenia sobie z tym - innodb_pass_corrupt_table.
Sasha Pachev

1
Szukałem tego rodzaju informacji z ostatnich 3 dni, teraz mam to. InnoDB jest najlepszy. DziękiBill Karwin
użytkownik3833682,

3
@ flow2k, Obecnie prawie nie ma. W mojej ostatniej pracy korzystaliśmy z MyISAM dla jednej tabeli na jednym serwerze, a jedynym powodem było to, że MyISAM był w stanie przechowywać tę konkretną tabelę na mniejszej przestrzeni niż InnoDB. Ograniczono nam przestrzeń dyskową, więc musieliśmy używać MyISAM, dopóki nie będziemy mogli przenieść bazy danych na inny serwer. W mojej nowej pracy istnieje już zasada, że ​​każdy stół musi być InnoDB.
Bill Karwin

138

Pracowałem na systemie o dużej objętości za pomocą MySQL i wypróbowałem zarówno MyISAM, jak i InnoDB.

Odkryłem, że blokowanie na poziomie tabeli w MyISAM spowodowało poważne problemy z wydajnością naszego obciążenia, które brzmi podobnie do twojego. Niestety odkryłem również, że wydajność pod InnoDB była gorsza niż się spodziewałem.

W końcu rozwiązałem problem rywalizacji, dzieląc dane tak, że wstawki trafiły do ​​„gorącej” tabeli i selekcje nigdy nie przeszukiwały gorącej tabeli.

Pozwoliło to również na usunięcie (dane były wrażliwe na czas i zachowaliśmy tylko X dni) na „przestarzałych” tabelach, których ponownie nie dotknęły wybrane zapytania. Wydaje się, że InnoDB ma niską wydajność przy usuwaniu zbiorczym, więc jeśli planujesz wyczyścić dane, możesz chcieć uporządkować je w taki sposób, aby stare dane były w starej tabeli, którą można po prostu usunąć zamiast uruchamiać na niej usuwanie.

Oczywiście nie mam pojęcia, jaka jest twoja aplikacja, ale mam nadzieję, że daje to wgląd w niektóre problemy z MyISAM i InnoDB.


3
„Ostatecznie rozwiązałem problem rywalizacji, dzieląc dane w taki sposób, że wstawki trafiły do„ gorącej ”tabeli i selekcje nigdy nie pytały o gorącą tabelę.” - czy nie jest to zasadniczo po co jest pula buforów ?
BlueRaja - Danny Pflughoeft

15
Danny - Nie, niezupełnie. Strojenie ustawień serwera jest ważne, ale w żaden sposób nie może zastąpić przemyślanej struktury schematu. Jeśli masz DB dużo, dużo większą niż dostępna pamięć RAM i wzorce dostępu, które dotykają danych losowo w całej DB, wówczas całe strojenie puli buforów na świecie nie pomoże. Jeśli rozumiesz dane i wzorce dostępu, możesz złagodzić wiele bólu poprzez staranne zaprojektowanie.
alanc10n

66

Trochę za późno na grę ... ale oto dość obszerny post, który napisałem kilka miesięcy temu , opisując główne różnice między MYISAM a InnoDB. Chwyć cuppa (a może herbatniki) i ciesz się.


Główną różnicą między MyISAM a InnoDB jest integralność referencyjna i transakcje. Istnieją również inne różnice, takie jak blokowanie, wycofywanie zmian i wyszukiwanie pełnotekstowe.

Więzy integralności

Integralność referencyjna zapewnia spójność relacji między tabelami. Mówiąc dokładniej, oznacza to, że gdy tabela (np. Listy) ma klucz obcy (np. Identyfikator produktu) wskazujący inną tabelę (np. Produkty), gdy aktualizacje lub usunięcia wystąpią w tabeli wskazanej, zmiany te są kaskadowane do łączenia stół. W naszym przykładzie, jeśli nazwa produktu zostanie zmieniona, klucze obce tabeli łączącej również się zaktualizują; jeśli produkt zostanie usunięty z tabeli „Produkty”, wszelkie wykazy wskazujące na usunięty wpis również zostaną usunięte. Ponadto każdy nowy wpis musi mieć ten klucz obcy wskazujący prawidłowy, istniejący wpis.

InnoDB jest relacyjnym DBMS (RDBMS), a zatem ma integralność referencyjną, podczas gdy MyISAM nie.

Transakcje i atomowość

Dane w tabeli są zarządzane za pomocą instrukcji DML (Data Manipulation Language), takich jak SELECT, INSERT, UPDATE i DELETE. Transakcja grupuje dwie lub więcej instrukcji DML razem w jedną jednostkę pracy, więc albo stosowana jest cała jednostka, albo żadna z niej nie jest.

MyISAM nie obsługuje transakcji, podczas gdy InnoDB obsługuje.

Jeśli operacja zostanie przerwana podczas korzystania z tabeli MyISAM, operacja zostanie natychmiast przerwana, a zmienione wiersze (lub nawet dane w każdym wierszu) pozostaną niezmienione, nawet jeśli operacja nie zostanie ukończona.

Jeśli operacja zostanie przerwana podczas korzystania z tabeli InnoDB, ponieważ wykorzystuje ona transakcje o atomowości, każda transakcja, która nie została zakończona, nie wejdzie w życie, ponieważ nie zostanie wykonane zatwierdzenie.

Blokowanie tabeli a blokowanie wiersza

Gdy zapytanie działa przeciwko tabeli MyISAM, cała tabela, w której jest wysyłana, zostanie zablokowana. Oznacza to, że kolejne zapytania będą wykonywane dopiero po zakończeniu bieżącego. Jeśli czytasz dużą tabelę i / lub często występują operacje odczytu i zapisu, może to oznaczać ogromne zaległości w zapytaniach.

Gdy zapytanie działa przeciwko tabeli InnoDB, tylko zaangażowane wiersze są zablokowane, reszta tabeli pozostaje dostępna dla operacji CRUD. Oznacza to, że zapytania mogą być uruchamiane jednocześnie w tej samej tabeli, pod warunkiem, że nie używają tego samego wiersza.

Ta funkcja w InnoDB jest znana jako współbieżność. Niezależnie od tego, jak duża jest współbieżność, istnieje poważna wada, która ma zastosowanie do wybranego zakresu tabel, polegająca na tym, że przełączanie między wątkami jądra wiąże się z narzutem, i powinieneś ustawić limit wątków jądra, aby zapobiec zatrzymaniu się serwera .

Transakcje i wycofania

Po uruchomieniu operacji w MyISAM zmiany są ustawiane; w InnoDB zmiany te można wycofać. Najpopularniejsze polecenia używane do kontrolowania transakcji to COMMIT, ROLLBACK i SAVEPOINT. 1. COMMIT - możesz napisać wiele operacji DML, ale zmiany zostaną zapisane dopiero po wykonaniu COMMIT 2. ROLLBACK - możesz odrzucić wszelkie operacje, które nie zostały jeszcze zatwierdzone 3. SAVEPOINT - ustawia punkt na liście operacje, do których można przywrócić operację ROLLBACK

Niezawodność

MyISAM nie zapewnia integralności danych - awarie sprzętu, nieczyste wyłączenia i anulowane operacje mogą spowodować uszkodzenie danych. Wymagałoby to pełnej naprawy lub przebudowy indeksów i tabel.

InnoDB, z drugiej strony, wykorzystuje dziennik transakcji, bufor podwójnego zapisu oraz automatyczne sumowanie i sprawdzanie, aby zapobiec uszkodzeniu. Przed wprowadzeniem jakichkolwiek zmian InnoDB zapisuje dane przed transakcjami w pliku obszaru tabel o nazwie ibdata1. W przypadku awarii InnoDB automatycznie odzyskałby zawartość poprzez odtworzenie tych dzienników.

Indeksowanie FULLTEXT

InnoDB nie obsługuje indeksowania FULLTEXT, dopóki MySQL w wersji 5.6.4. W chwili pisania tego postu wersja MySQL wielu dostawców hostingu współdzielonego jest nadal niższa niż 5.6.4, co oznacza, że ​​indeksowanie FULLTEXT nie jest obsługiwane dla tabel InnoDB.

Nie jest to jednak uzasadniony powód do korzystania z MyISAM. Najlepiej jest zmienić się na dostawcę usług hostingowych, który obsługuje aktualne wersje MySQL. Nie dlatego, że tabela MyISAM, która korzysta z indeksowania FULLTEXT, nie może zostać przekonwertowana na tabelę InnoDB.

Wniosek

Podsumowując, InnoDB powinien być twoim domyślnym silnikiem pamięci. Wybierz MyISAM lub inne typy danych, jeśli spełniają one określone potrzeby.


Tworzyłem skrypt sumy kontrolnej sesji php i większość mojego klucza to losowe ciągi [az09] ... Innodb zajęło mi to 30ms, INSERT ON DUPLICATE KEY UPDATEwięc wypróbowałem MyISAM, a teraz jest to <1ms ... Wiele odpowiedzi, które widziałem, mówią, że innodb z trudem radzi sobie z unikalnymi kluczami „nieprzenośnymi” (losowymi ciągami) ... Czy masz na to jakiś wpływ? W rzeczywistości zastanawiałem się, jaki wpływ będzie miało korzystanie z MyISAM, ale twoja świetna odpowiedź uświadomiła mi, że jest to właściwy sposób na rozwiązanie tego konkretnego przypadku.
Louis Loudog Trottier

64

W przypadku obciążenia z większą liczbą zapisów i odczytów skorzystasz z InnoDB. Ponieważ InnoDB zapewnia blokowanie wierszy zamiast blokowania tabeli, twoje SELECTs mogą być współbieżne, nie tylko ze sobą, ale także z wieloma INSERTs. Jeśli jednak nie zamierzasz używać transakcji SQL, ustaw kolor zatwierdzania InnoDB na 2 ( innodb_flush_log_at_trx_commit ). To daje ci dużo surowej wydajności, którą inaczej straciłbyś, przenosząc tabele z MyISAM do InnoDB.

Rozważ także dodanie replikacji. Daje to trochę skalowania odczytu, a ponieważ stwierdziłeś, że twoje odczyty nie muszą być aktualne, możesz pozwolić, aby replikacja pozostała w tyle. Tylko upewnij się, że może nadrobić zaległości pod każdym ruchem, z wyjątkiem największego ruchu, bo zawsze będzie w tyle i nigdy go nie dogoni. Jeśli jednak pójdziesz tą drogą, zdecydowanie zalecamy odizolowanie odczytu od urządzeń podrzędnych i zarządzania opóźnieniami replikacji w module obsługi bazy danych. Jest to o wiele prostsze, jeśli kod aplikacji nie wie o tym.

Wreszcie, należy pamiętać o różnych obciążeniach tabeli. Nie będziesz mieć takiego samego współczynnika odczytu / zapisu we wszystkich tabelach. Niektóre mniejsze stoły z prawie 100% odczytów mogą pozwolić sobie na pozostanie MyISAM. Podobnie, jeśli masz tabele, które są w 100% w stanie zapisać, możesz skorzystać INSERT DELAYED, ale jest to obsługiwane tylko w MyISAM ( DELAYEDklauzula jest ignorowana dla tabeli InnoDB).

Ale na pewno benchmark.


4
Czy jest to „Flush zatwierdzenia InnoDB”, o którym mówisz innodb_flush_log_at_trx_commit?
ceejayoz,

2
Uznałem twój post za bardzo przydatny - dzięki. Obecnie oceniam, kiedy używać MyISAM / InnoDB do moich tabel, a Twój post był pomocny. Twoje zdrowie.
starmonkey

2
dev.mysql.com/doc/refman/5.5/en/insert-delayed.html stwierdza: W przypadku tabel MyISAM, jeśli w środku pliku danych nie ma wolnych bloków, obsługiwane są instrukcje SELECT i INSERT. W tych okolicznościach bardzo rzadko trzeba używać INSERT DELAYED z MyISAM.
tymtam

Bardzo pouczający post. Mam takie samo pytanie jak w op i muszę powiedzieć, że twój post uspokoił mnie w związku z decyzją dotyczącą silnika bazy danych. Dzięki! ++
Joe Majewski,

Szybka uwaga: opóźnienie nie jest już obsługiwane w 5.7. Zamiast tego możesz przetestować za pomocą LOW_PRIORITY.
webmat

59

Aby dodać do szerokiego wyboru odpowiedzi obejmujących różnice mechaniczne między dwoma silnikami, przedstawiam empiryczne badanie porównania prędkości.

Jeśli chodzi o czystą prędkość, nie zawsze jest tak, że MyISAM jest szybszy niż InnoDB, ale z mojego doświadczenia wynika, że ​​jest on szybszy w środowiskach roboczych PURE READ około 2,0-2,5 razy. Oczywiście nie jest to odpowiednie dla wszystkich środowisk - jak napisali inni, w MyISAM brakuje takich rzeczy, jak transakcje i klucze obce.

Poniżej przeprowadziłem trochę testów porównawczych - użyłem Pythona do zapętlenia i biblioteki timeit do porównań czasowych. Dla zainteresowania załączyłem również silnik pamięci, który zapewnia najlepszą wydajność na całej płycie, chociaż jest odpowiedni tylko dla mniejszych tabel (ciągle napotykasz, The table 'tbl' is fullgdy przekroczysz limit pamięci MySQL). Cztery typy wybranych, na które patrzę, to:

  1. wanilia WYBIERA
  2. liczy się
  3. WYBORY warunkowe
  4. indeksowane i nieindeksowane podselekcje

Po pierwsze, utworzyłem trzy tabele, używając następującego SQL

CREATE TABLE
    data_interrogation.test_table_myisam
    (
        index_col BIGINT NOT NULL AUTO_INCREMENT,
        value1 DOUBLE,
        value2 DOUBLE,
        value3 DOUBLE,
        value4 DOUBLE,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8

z „MyISAM” zamienionymi na „InnoDB” i „memory” w drugiej i trzeciej tabeli.

 

1) Wanilia wybiera

Pytanie: SELECT * FROM tbl WHERE index_col = xx

Wynik: remis

Porównanie wyborów waniliowych według różnych silników baz danych

Ich prędkość jest zasadniczo taka sama i zgodnie z oczekiwaniami jest liniowa w liczbie kolumn do wyboru. InnoDB wydaje się nieco szybszy niż MyISAM, ale jest to naprawdę marginalne.

Kod:

import timeit
import MySQLdb
import MySQLdb.cursors
import random
from random import randint

db = MySQLdb.connect(host="...", user="...", passwd="...", db="...", cursorclass=MySQLdb.cursors.DictCursor)
cur = db.cursor()

lengthOfTable = 100000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)
    cur.execute(insertString3)

db.commit()

# Define a function to pull a certain number of records from these tables
def selectRandomRecords(testTable,numberOfRecords):

    for x in xrange(numberOfRecords):
        rand1 = randint(0,lengthOfTable)

        selectString = "SELECT * FROM " + testTable + " WHERE index_col = " + str(rand1)
        cur.execute(selectString)

setupString = "from __main__ import selectRandomRecords"

# Test time taken using timeit
myisam_times = []
innodb_times = []
memory_times = []

for theLength in [3,10,30,100,300,1000,3000,10000]:

    innodb_times.append( timeit.timeit('selectRandomRecords("test_table_innodb",' + str(theLength) + ')', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('selectRandomRecords("test_table_myisam",' + str(theLength) + ')', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('selectRandomRecords("test_table_memory",' + str(theLength) + ')', number=100, setup=setupString) )

 

2) Liczy się

Pytanie: SELECT count(*) FROM tbl

Wynik: MyISAM wygrywa

Porównanie liczby różnych silników baz danych

Ten pokazuje dużą różnicę między MyISAM a InnoDB - MyISAM (i pamięć) śledzi liczbę rekordów w tabeli, więc transakcja jest szybka, a O (1). Ilość czasu potrzebna do zliczenia InnoDB wzrasta superliniowo wraz z rozmiarem stołu w badanym zakresie. Podejrzewam, że wiele przyspieszeń z zapytań MyISAM, które są obserwowane w praktyce, wynika z podobnych efektów.

Kod:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to count the records
def countRecords(testTable):

    selectString = "SELECT count(*) FROM " + testTable
    cur.execute(selectString)

setupString = "from __main__ import countRecords"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('countRecords("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('countRecords("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('countRecords("test_table_memory")', number=100, setup=setupString) )

 

3) Wybór warunkowy

Pytanie: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

Wynik: MyISAM wygrywa

Porównanie selekcji warunkowych przez różne silniki baz danych

Tutaj MyISAM i pamięć działają mniej więcej tak samo i pokonały InnoDB o około 50% w przypadku większych tabel. Jest to rodzaj zapytania, w przypadku którego korzyści MyISAM wydają się zmaksymalizowane.

Kod:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to perform conditional selects
def conditionalSelect(testTable):
    selectString = "SELECT * FROM " + testTable + " WHERE value1 < 0.5 AND value2 < 0.5 AND value3 < 0.5 AND value4 < 0.5"
    cur.execute(selectString)

setupString = "from __main__ import conditionalSelect"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('conditionalSelect("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('conditionalSelect("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('conditionalSelect("test_table_memory")', number=100, setup=setupString) )

 

4) Podselekcja

Wynik: InnoDB wygrywa

Dla tego zapytania utworzyłem dodatkowy zestaw tabel dla podselekcji. Każda z nich to po prostu dwie kolumny BIGINT, jedna z indeksem klucza podstawowego i jedna bez indeksu. Ze względu na duży rozmiar stołu nie testowałem silnika pamięci. Komenda tworzenia tabeli SQL była

CREATE TABLE
    subselect_myisam
    (
        index_col bigint NOT NULL,
        non_index_col bigint,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8;

gdzie ponownie „MyISAM” zastępuje się „InnoDB” w drugiej tabeli.

W tym zapytaniu zostawiam rozmiar tabeli wyboru na 1000000 i zamiast tego zmieniam rozmiar subselekcji kolumn.

Porównanie podselekcji według różnych silników baz danych

Tutaj InnoDB wygrywa łatwo. Po przejściu do rozsądnej tabeli rozmiarów oba silniki skalują się liniowo z rozmiarem podselekcji. Indeks przyspiesza polecenie MyISAM, ale co ciekawe, ma niewielki wpływ na szybkość InnoDB. subSelect.png

Kod:

myisam_times = []
innodb_times = []
myisam_times_2 = []
innodb_times_2 = []

def subSelectRecordsIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString = "from __main__ import subSelectRecordsIndexed"

def subSelectRecordsNotIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT non_index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString2 = "from __main__ import subSelectRecordsNotIndexed"

# Truncate the old tables, and re-fill with 1000000 records
truncateString = "TRUNCATE test_table_innodb"
truncateString2 = "TRUNCATE test_table_myisam"

cur.execute(truncateString)
cur.execute(truncateString2)

lengthOfTable = 1000000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)

for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE subselect_innodb"
    truncateString2 = "TRUNCATE subselect_myisam"

    cur.execute(truncateString)
    cur.execute(truncateString2)

    # For each length, empty the table and re-fill it with random data
    rand_sample = sorted(random.sample(xrange(lengthOfTable), theLength))
    rand_sample_2 = random.sample(xrange(lengthOfTable), theLength)

    for (the_value_1,the_value_2) in zip(rand_sample,rand_sample_2):
        insertString = "INSERT INTO subselect_innodb (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"
        insertString2 = "INSERT INTO subselect_myisam (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)

    db.commit()

    # Finally, time the queries
    innodb_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString) )

    innodb_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString2) )
    myisam_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString2) )

Myślę, że przesłaniem tego wszystkiego jest to, że jeśli naprawdę martwisz się szybkością, musisz przeprowadzić analizę porównawczą zapytań, a nie założyć, który silnik będzie bardziej odpowiedni.


1
wydajność nie zawsze jest jedyną kwestią, a może wykres o stabilności? silnik nie nadaje się do niczego, jeśli ulega awarii i nie obsługuje podstawowych funkcji bazy danych.
pilavdzice

1
MyISAM prawdopodobnie przebije InnoDB przez większość czasu, jeśli my.cnfplik nie będzie zoptymalizowany pod kątem InnoDB. Nie wspomniałeś o tym, jak my.cnfwygląda twój plik, co jest naprawdę najważniejszym czynnikiem wpływającym na wydajność InnoDB.
itoctopus

Dzięki itoctopus - Chciałbym usłyszeć więcej o wszelkich zaleceniach dotyczących optymalizacji. Pełny kod użyty w tych testach znajduje się powyżej, możesz powtórzyć eksperymenty z różnymi optymalizacjami i daj nam znać, jeśli znajdziesz znaczące zmiany w wynikach
StackG

32

Nieco nie na temat, ale dla celów dokumentacji i kompletności chciałbym dodać następujące.

Ogólnie rzecz biorąc, użycie InnoDB spowoduje znacznie MNIEJSZĄ złożoną aplikację, prawdopodobnie również bardziej wolną od błędów. Ponieważ możesz włożyć całą integralność referencyjną (ograniczenia klucza obcego) do modelu danych, nie potrzebujesz tak blisko kodu aplikacji, ile potrzebujesz w MyISAM.

Za każdym razem, gdy wstawisz, usuniesz lub zastąpisz rekord, MUSISZ sprawdzić i zachować relacje. Np. Jeśli usuniesz rodzica, wszystkie dzieci również powinny zostać usunięte. Na przykład, nawet w prostym systemie blogowym, jeśli usuniesz rekord blogowania, będziesz musiał usunąć rekordy komentarzy, polubienia itp. W InnoDB jest to wykonywane automatycznie przez silnik bazy danych (jeśli określiłeś ograniczenia w modelu ) i nie wymaga kodu aplikacji. W MyISAM będzie to musiało zostać zakodowane w aplikacji, co jest bardzo trudne na serwerach internetowych. Serwery sieciowe są z natury bardzo równoległe / równoległe, a ponieważ te działania powinny być atomowe, a MyISAM nie obsługuje rzeczywistych transakcji, używanie MyISAM do serwerów internetowych jest ryzykowne / podatne na błędy.

Również w większości ogólnych przypadków InnoDB będzie działał znacznie lepiej, z wielu powodów, z których jeden może używać blokowania na poziomie rekordu w przeciwieństwie do blokowania na poziomie tabeli. Nie tylko w sytuacji, gdy zapisy są częstsze niż odczyty, ale także w sytuacjach ze złożonymi połączeniami na dużych zestawach danych. Zauważyliśmy 3-krotny wzrost wydajności tylko przy użyciu tabel InnoDB w stosunku do tabel MyISAM dla bardzo dużych złączeń (zajmuje to kilka minut).

Powiedziałbym, że ogólnie InnoDB (przy użyciu modelu danych 3NF z integralnością referencyjną) powinien być domyślnym wyborem podczas korzystania z MySQL. MyISAM powinien być używany tylko w bardzo szczególnych przypadkach. Najprawdopodobniej będzie działał mniej, powodując większą i bardziej błędną aplikację.

To powiedziawszy. Datamodelling jest sztuką rzadko spotykaną wśród projektantów / programistów. Bez obrazy, ale tłumaczy to, że MyISAM jest tak często używany.


31

InnoDB oferuje:

ACID transactions
row-level locking
foreign key constraints
automatic crash recovery
table compression (read/write)
spatial data types (no spatial indexes)

W InnoDB wszystkie dane z rzędu oprócz TEKSTU i BLOBA mogą zajmować maksymalnie 8 000 bajtów. Indeksowanie pełnotekstowe nie jest dostępne dla InnoDB. W InnoDB COUNT (*) s (gdy GDZIE, GROUP BY lub JOIN nie są używane) działają wolniej niż w MyISAM, ponieważ liczba wierszy nie jest przechowywana wewnętrznie. InnoDB przechowuje zarówno dane, jak i indeksy w jednym pliku. InnoDB używa puli buforów do buforowania zarówno danych, jak i indeksów.

MyISAM oferuje:

fast COUNT(*)s (when WHERE, GROUP BY, or JOIN is not used)
full text indexing
smaller disk footprint
very high table compression (read only)
spatial data types and indexes (R-tree)

MyISAM ma blokowanie na poziomie tabeli, ale nie blokuje na poziomie wiersza. Brak transakcji. Brak automatycznego odzyskiwania po awarii, ale oferuje funkcje tabeli napraw. Brak ograniczeń klucza obcego. Tabele MyISAM są na ogół bardziej kompaktowe na dysku w porównaniu do tabel InnoDB. Tabele MyISAM można dodatkowo znacznie zmniejszyć, kompresując myisampack, jeśli to konieczne, ale stać się tylko do odczytu. MyISAM przechowuje indeksy w jednym pliku, a dane w innym. MyISAM używa buforów kluczy do buforowania indeksów i pozostawia zarządzanie buforowaniem danych w systemie operacyjnym.

Ogólnie polecam InnoDB do większości celów, a MyISAM tylko do specjalistycznych zastosowań. InnoDB jest teraz domyślnym silnikiem w nowych wersjach MySQL.


2
fwiw, VARCHAR w InnoDB może również przechodzić do stron przepełnienia, takich jak BLOB i TEXT. Wszystkie te typy danych są przechowywane wewnętrznie podobnie.
Bill Karwin

Dobrze wiedzieć, @BillKarwin! Bardzo często korzystamy z VARCHAR w naszej aplikacji, a udział VARCHAR w tym limicie ~ 8kB był nieco niepokojący.
rinogo,


odpowiedź nie jest już aktualna, ponieważ silnik innodb w MySQL w wersji 5.6+ obecnie obsługuje również indeksowanie pełnotekstowe, a także MySQL 5.5 + / 5.7 + obsługuje typy danych przestrzennych (5.5+) i indeksy przestrzenne (r-tee) (5.7+) .. Aby uzyskać najlepsze wsparcie, musisz mieć przynajmniej MySQL w wersji 5.7+
Raymond Nijland

25

Jeśli korzystasz z MyISAM, nie będziesz wykonywać żadnych transakcji na godzinę, chyba że weźmiesz pod uwagę każdą instrukcję DML jako transakcję (która w żadnym wypadku nie będzie trwała ani atomowa w przypadku awarii).

Dlatego myślę, że musisz użyć InnoDB.

300 transakcji na sekundę to całkiem sporo. Jeśli absolutnie potrzebujesz, aby transakcje te były trwałe w przypadku awarii zasilania, upewnij się, że podsystem we / wy może łatwo obsłużyć tak wiele operacji zapisu na sekundę. Potrzebny będzie co najmniej kontroler RAID z pamięcią podręczną podtrzymywaną bateryjnie.

Jeśli możesz wziąć małe uderzenie o wytrzymałość, możesz użyć InnoDB z innodb_flush_log_at_trx_commit ustawioną na 0 lub 2 (szczegóły w dokumentacji), możesz poprawić wydajność.

Istnieje wiele poprawek, które mogą zwiększyć współbieżność od Google i innych - mogą być interesujące, jeśli nadal nie możesz uzyskać wystarczającej wydajności bez nich.


24

Pytanie i większość odpowiedzi są nieaktualne .

Tak, to opowieść starych żon, że MyISAM jest szybszy niż InnoDB. zauważ datę pytania: 2008; jest teraz prawie dekadę później. Od tego czasu InnoDB poczyniło znaczne postępy w zakresie wydajności.

Dramatyczna wykres był za jednego przypadku MyISAM Wygrane: COUNT(*) bez pomocą WHEREklauzuli. Ale czy tak naprawdę spędzasz czas?

Jeśli uruchomisz test współbieżności , bardzo prawdopodobne jest, że InnoDB wygra, nawet przeciwkoMEMORY .

Jeśli piszesz podczas porównywania SELECTs, MyISAM iMEMORY prawdopodobnie stracą z powodu blokowania na poziomie tabeli.

W rzeczywistości Oracle jest tak pewien, że InnoDB jest lepszy, że usunęły MyISAM z wersji 8.0.

Pytanie zostało napisane na początku czasów 5.1. Od tego czasu te główne wersje zostały oznaczone jako „Ogólna dostępność”:

  • 2010: 5,5 (0,8 w grudniu)
  • 2013: 5.6 (.10 w lutym)
  • 2015: 5,7 (.9 w październiku)
  • 2018: 8.0 (.11 w kwietniu)

Konkluzja: Nie używaj MyISAM


2
Postępy w technologii baz danych MySQL. Pytanie i odpowiedzi StackOverflow pozostają w przeszłości w błędzie. Te główne różnice między MyISAM i InnoDB są mniej o „obciążenie” na serwerze, a bardziej o wsparcie dla więzy integralności i transakcji , a także współbieżności i odzysku (+10)
spencer7593

12

Sprawdź także niektóre zastępcze zamienniki dla samego MySQL:

MariaDB

http://mariadb.org/

MariaDB to serwer bazy danych, który oferuje funkcję zastępowania MySQL. MariaDB została zbudowana przez niektórych oryginalnych autorów MySQL, przy wsparciu szerszej społeczności programistów tworzących bezpłatne i otwarte oprogramowanie. Oprócz podstawowej funkcjonalności MySQL, MariaDB oferuje bogaty zestaw ulepszeń funkcji, w tym alternatywne silniki pamięci masowej, optymalizacje serwerów i łatki.

Serwer Percona

https://launchpad.net/percona-server

Ulepszone zastępowanie MySQL, z lepszą wydajnością, ulepszoną diagnostyką i dodanymi funkcjami.


1
Używam obu z nich (Percona w produkcji, Maria na rozwoju okien). są szybsze i działają perfekcyjnie.
Mosze L

4
To nie odpowiada na pytanie. MariaDB i Percona są rozwidleniami MySQL i używają także silników InnoDB i MyISAM.
dr_

12

Proszę zauważyć, że moje formalne wykształcenie i doświadczenie dotyczy Oracle, podczas gdy moja praca z MySQL była całkowicie osobista i odbywa się w moim własnym czasie, więc jeśli powiem rzeczy, które są prawdziwe dla Oracle, ale nie są prawdziwe dla MySQL, przepraszam. Podczas gdy oba systemy mają wiele wspólnego, relacyjna teoria / algebra jest taka sama, a relacyjne bazy danych są nadal relacyjnymi bazami danych, wciąż istnieje wiele różnic !!

Szczególnie podoba mi się (podobnie jak blokowanie na poziomie wiersza), że InnoDB jest oparty na transakcjach, co oznacza, że ​​możesz aktualizować / wstawiać / tworzyć / zmieniać / upuszczać / itp. Kilka razy dla jednej „operacji” swojej aplikacji internetowej. Problemem, który się pojawia, jest to, że tylko niektóre z tych zmian / operacji zostaną ostatecznie zatwierdzone, a inne nie, to najczęściej będziesz (w zależności od konkretnego projektu bazy danych) skończył z bazą danych o sprzecznych danych / strukturze.

Uwaga: W przypadku Oracle instrukcje tworzenia / zmiany / upuszczenia są nazywane instrukcjami „DDL” (definicja danych) i domyślnie wyzwalają zatwierdzenie. Instrukcje wstawiania / aktualizacji / usuwania, zwane „DML” (przetwarzanie danych), nie są zatwierdzane automatycznie, ale tylko wtedy, gdy wykonywany jest DDL, zatwierdzenie lub wyjście / wyjście (lub jeśli ustawisz sesję na „automatyczne zatwierdzanie” lub jeśli twój klient automatycznie się zatwierdzi). Należy pamiętać o tym podczas pracy z Oracle, ale nie jestem pewien, jak MySQL obsługuje te dwa typy instrukcji. Z tego powodu chcę wyjaśnić, że nie jestem tego pewien, jeśli chodzi o MySQL; tylko z Oracle.

Przykład doskonałości silników opartych na transakcjach:

Powiedzmy, że ja lub ty jesteś na stronie internetowej, aby zarejestrować się, aby wziąć udział w bezpłatnym wydarzeniu, a jednym z głównych celów systemu jest umożliwienie zarejestrowania się maksymalnie 100 osobom, ponieważ jest to limit miejsc na wydarzenie. Po osiągnięciu 100 rejestracji system wyłączy kolejne rejestracje, przynajmniej dopóki inne nie anulują.

W takim przypadku może istnieć stół dla gości (imię i nazwisko, telefon, e-mail itp.) Oraz drugi stół, który śledzi liczbę zarejestrowanych gości. Mamy zatem dwie operacje dla jednej „transakcji”. Załóżmy teraz, że po dodaniu informacji o gościu do tabeli GOŚCI występuje utrata połączenia lub błąd o takim samym wpływie. Tabela GOŚCI została zaktualizowana (wstawiona), ale połączenie zostało utracone, zanim „dostępne miejsca” mogły zostać zaktualizowane.

Teraz mamy gościa dodanego do stołu gości, ale liczba dostępnych miejsc jest teraz niepoprawna (na przykład wartość wynosi 85, gdy w rzeczywistości wynosi 84).

Oczywiście istnieje wiele sposobów, aby sobie z tym poradzić, na przykład śledzenie dostępnych miejsc za pomocą „100 minus liczba wierszy w tabeli gości” lub kodu, który sprawdza, czy informacje są spójne itp. Ale z bazą danych opartą na transakcjach silnik taki jak InnoDB, albo WSZYSTKIE operacje są zatwierdzone, albo ŻADNA z nich nie jest. Może to być pomocne w wielu przypadkach, ale tak jak powiedziałem, nie jest to JEDYNY sposób na bezpieczeństwo, nie (fajny sposób obsługiwany przez bazę danych, a nie programistę / programistę).

To wszystko „oparte na transakcjach” zasadniczo oznacza w tym kontekście, chyba że czegoś mi brakuje - że albo cała transakcja się powiedzie, jak powinna, albo nic się nie zmieni, ponieważ dokonanie tylko częściowych zmian może sprawić, że POTĘŻNY bałagan baza danych, może nawet ją psuje ...

Ale powiem to jeszcze raz, to nie jedyny sposób na uniknięcie bałaganu. Jest to jednak jedna z metod obsługiwanych przez sam silnik, pozostawiając użytkownika do pisania kodu / skryptu, który wymaga jedynie martwienia się o to, czy transakcja się powiodła, czy też nie, a co mam zrobić, jeśli nie (np. Spróbować ponownie) zamiast ręcznie pisząc kod, aby sprawdzać go „ręcznie” spoza bazy danych i wykonując znacznie więcej pracy w przypadku takich zdarzeń.

Na koniec uwaga na temat blokowania tabel vs blokowania wierszy:

WYŁĄCZENIE ODPOWIEDZIALNOŚCI: Mogę się mylić we wszystkich poniższych kwestiach dotyczących MySQL, a hipotetyczne / przykładowe sytuacje są sprawami do rozważenia, ale mogę się mylić, co dokładnie jest możliwe, aby spowodować uszkodzenie w MySQL. Przykłady są jednak bardzo prawdziwe w ogólnym programowaniu, nawet jeśli MySQL ma więcej mechanizmów, aby uniknąć takich rzeczy ...

W każdym razie, jestem dość pewny zgadzając się z tymi, którzy twierdzą, że ilu połączenia są dozwolone w danym momencie nie nie obejść zablokowaną tabelę. W rzeczywistości wiele połączeń to cały punkt blokowania stołu !! Aby inne procesy / użytkownicy / aplikacje nie mogły uszkodzić bazy danych, wprowadzając jednocześnie zmiany.

W jaki sposób dwa lub więcej połączeń pracujących w tym samym rzędzie NAPRAWDĘ ZŁO dla Ciebie? Załóżmy, że istnieją dwa procesy, które chcą / muszą zaktualizować tę samą wartość w tym samym rzędzie, powiedzmy, ponieważ wiersz jest zapisem trasy autobusu, a każdy z dwóch procesów jednocześnie chce zaktualizować „jeźdźców” lub „dostępne_siady” pole jako „aktualna wartość plus 1.”

Zróbmy to hipotetycznie, krok po kroku:

  1. Proces jeden odczytuje bieżącą wartość, powiedzmy, że jest pusta, a zatem jak dotąd „0”.
  2. Proces drugi odczytuje również bieżącą wartość, która wciąż wynosi 0.
  3. Przetwarzaj jeden zapis (bieżący + 1), który wynosi 1.
  4. Proces drugi powinien zapisywać 2, ale ponieważ odczytuje bieżącą wartość przed procesem pierwszym zapisuje nową wartość, również zapisuje 1 do tabeli.

Nie jestem pewien, czy dwa połączenia mogą się tak przenikać, oba czytają przed pierwszym, który pisze ... Ale jeśli nie, to nadal będę mieć problem z:

  1. Proces jeden odczytuje bieżącą wartość, która wynosi 0.
  2. Proces jeden pisze (bieżący + 1), który wynosi 1.
  3. Proces dwa odczytuje teraz bieżącą wartość. Ale podczas przetwarzania jednego zapisu DID (aktualizacji), nie zatwierdził danych, dlatego tylko ten sam proces może odczytać nową wartość, którą zaktualizował, podczas gdy wszystkie inne widzą starszą wartość, aż do zatwierdzenia.

Ponadto, przynajmniej w przypadku baz danych Oracle, istnieją poziomy izolacji, których nie będę marnować czasu na próby parafrazowania. Oto dobry artykuł na ten temat, a każdy poziom izolacji ma swoje zalety i wady, co pasowałoby do tego, jak ważne mogą być silniki bazujące na transakcjach w bazie danych ...

Wreszcie, w MyISAM mogą istnieć różne zabezpieczenia zamiast kluczy obcych i interakcji opartych na transakcjach. Po pierwsze, istnieje fakt, że cały stół jest zablokowany, co zmniejsza prawdopodobieństwo, że potrzebne są transakcje / FK .

I niestety, jeśli zdajesz sobie sprawę z tych problemów z współbieżnością, tak, możesz grać mniej bezpiecznie i po prostu pisać aplikacje, konfigurować systemy tak, aby takie błędy nie były możliwe (wtedy twój kod jest odpowiedzialny, a nie sama baza danych). Jednak moim zdaniem powiedziałbym, że zawsze najlepiej jest stosować jak najwięcej zabezpieczeń, programować w sposób defensywny i zawsze mieć świadomość, że błędu ludzkiego nie da się całkowicie uniknąć. Zdarza się każdemu, a każdy, kto twierdzi, że jest na to odporny, musi kłamać lub nie zrobił nic więcej niż napisanie aplikacji / skryptu „Hello World”. ;-)

Mam nadzieję, że NIEKTÓRE z tych informacji są pomocne komuś, a tym bardziej, mam nadzieję, że nie tylko byłem teraz winowajcą założeń i popełniłem błąd! Przepraszam, jeśli tak, ale przykłady warto przemyśleć, zbadać ryzyko i tak dalej, nawet jeśli nie są potencjalne w tym konkretnym kontekście.

Popraw mnie, edytuj tę „odpowiedź”, a nawet głosuj w dół. Po prostu spróbuj poprawić, zamiast korygować moje złe założenie przy pomocy innego. ;-)

To moja pierwsza odpowiedź, więc proszę wybaczyć długość ze względu na wszystkie zastrzeżenia, itp. Po prostu nie chcę brzmieć arogancko, gdy nie jestem absolutnie pewien!



5

Z mojego doświadczenia wynika, że ​​MyISAM był lepszym wyborem, pod warunkiem, że nie usuwasz, nie aktualizujesz, wiele pojedynczych WSTAW, transakcji i indeksowania pełnotekstowego. BTW, TABELA KONTROLNA jest okropna. W miarę starzenia się tabeli pod względem liczby wierszy nie wiadomo, kiedy się skończy.


2
Indeksowanie pełnotekstowe jest możliwe tylko w MyISAM, a nie w InnoDB.
Pixel Elephant,

2
@PixelElephant, który zaczyna się zmieniać w MySQL 5.6. InnoDB ma typ indeksu pełnotekstowego, ale jak dotąd nie jest gotowy do użycia w produkcji IMHO.
Bill Karwin

1
„Indeksowanie pełnotekstowe jest możliwe tylko w MyISAM, a nie w InnoDB”: koniec z prawdą, ponieważ MySQL> = 5.6. Zobacz dev.mysql.com/doc/refman/5.6/en/fulltext-search.html .
Hibou57

5

Przekonałem się, że chociaż Myisam ma rywalizację o blokowanie, w większości scenariuszy wciąż jest szybsza niż InnoDb ze względu na używany schemat szybkiego pozyskiwania blokady. Próbowałem kilka razy Innodb i zawsze wracam do MyIsam z tego czy innego powodu. Również InnoDB może bardzo obciążać procesor przy dużych obciążeniach zapisu.


4

Każda aplikacja ma swój własny profil wydajności do korzystania z bazy danych i istnieje prawdopodobieństwo, że z czasem się zmieni.

Najlepsze, co możesz zrobić, to przetestować swoje opcje. Przełączanie między MyISAM i InnoDB jest banalne, więc załaduj dane testowe i uruchom jmeter na swojej stronie i zobacz, co się stanie.


4

Próbowałem uruchomić wstawianie losowych danych do tabel MyISAM i InnoDB. Wynik był dość szokujący. MyISAM potrzebował kilka sekund mniej na wstawienie 1 miliona wierszy niż InnoDB za zaledwie 10 tysięcy!


2
Otrzymasz taką samą wydajność, jeśli użyjesz transakcji i wyłączysz automatyczne zatwierdzanie dla silnika InnoDB.
stanleyxu2005

IDK, jeśli ta sama wydajność, ale to właśnie robię w bardziej złożonych aplikacjach i to przyspiesza.
user965748,

1
Nie udało się podać dokładnych szczegółów eksperymentu - jakie ustawienia konfiguracji? Co było wcześniej w tabelach? Jakie dane? a może co najważniejsze - czy były wstawki sekwencyjne? Równolegle? Jaki był ich czas? Ile rdzeni procesora? Wątki itp.
einpoklum

3

myisam jest NOGO dla tego typu obciążenia (zapisuje wysoką współbieżność), nie mam tyle doświadczenia z innodb (przetestowałem to 3 razy i w każdym przypadku stwierdziłem, że wydajność jest do bani, ale minęło trochę czasu od ostatniego testu), jeśli nie musisz uruchamiać mysql, rozważ wypróbowanie postgres, ponieważ obsługuje równoczesne pisanie DUŻO lepiej


3

Krótko mówiąc, InnoDB jest dobry, jeśli pracujesz nad czymś, co wymaga niezawodnej bazy danych, która może obsłużyć wiele instrukcji INSERT i UPDATE.

a MyISAM jest dobry, jeśli potrzebujesz bazy danych, która w większości wymaga dużo instrukcji odczytu (WYBIERZ) niż pisania (WSTAW i AKTUALIZACJE), biorąc pod uwagę jego wadę związaną z blokowaniem tabeli.

możesz sprawdzić;
Plusy i minusy InnoDB
Plusy i minusy MyISAM


2

Wiem, że to nie będzie popularne, ale oto:

myISAM nie obsługuje podstawowych danych bazy danych, takich jak transakcje i integralność referencyjna, co często skutkuje błędnymi / błędnymi aplikacjami. Nie można nauczyć się prawidłowych podstaw projektowania baz danych, jeśli nie są one nawet obsługiwane przez silnik db.

Niestosowanie integralności referencyjnej lub transakcji w świecie baz danych jest jak niestosowanie programowania obiektowego w świecie oprogramowania.

InnoDB już istnieje, użyj go zamiast tego! Nawet programiści MySQL w końcu zgodzili się na zmianę tego na domyślny silnik w nowszych wersjach, mimo że myISAM jest oryginalnym silnikiem, który był domyślny we wszystkich starszych systemach.

Nie, nie ma znaczenia, czy czytasz lub piszesz, czy jakie masz względy wydajnościowe, używanie myISAM może powodować różne problemy, takie jak ten, na który właśnie wpadłem: przeprowadzałem synchronizację bazy danych i jednocześnie kogoś innego uzyskał dostęp do aplikacji, która uzyskała dostęp do tabeli ustawionej na myISAM. Z powodu braku obsługi transakcji i ogólnie niskiej niezawodności tego silnika, to spowodowało awarię całej bazy danych i musiałem ręcznie ponownie uruchomić mysql!

W ciągu ostatnich 15 lat rozwoju korzystałem z wielu baz danych i silników. myISAM rozbił się na mnie kilkanaście razy w tym okresie, inne bazy danych, tylko raz! I to była baza danych Microsoft SQL, w której jakiś programista napisał wadliwy kod CLR (środowisko uruchomieniowe języka wspólnego - w zasadzie kod C #, który wykonuje się w bazie danych), przy okazji, to nie była wina silnika bazy danych.

Zgadzam się z innymi odpowiedziami, które mówią, że wysokiej jakości aplikacje o wysokiej dostępności i wydajności nie powinny używać myISAM, ponieważ nie będzie działać, nie jest wystarczająco solidny ani stabilny, aby zapewnić frustrację. Zobacz szczegóły Billa Karwina, aby uzyskać więcej informacji.

PS Uwielbiam to, gdy fani myISAM wyrażają opinię negatywnie, ale nie mogę powiedzieć, która część tej odpowiedzi jest nieprawidłowa.


5
nie głosowałem za głosem, ale gdybym to zrobił, byłoby doradzanie, aby nigdy nie używać. słowo nigdy nie powinno zostać zapisane w słowniku programisty… zastrzeżenie „nigdy nie mów nigdy”.
hubson bropa,

1

Dla tego stosunku odczytu / zapisu domyślam się, że InnoDB będzie działał lepiej. Ponieważ nie masz nic przeciwko brudnym odczytom, możesz (jeśli możesz sobie na to pozwolić) powielić się niewolnikowi i pozwolić, by wszystkie twoje odczyty przeszły do ​​niewolnika. Rozważ także wstawianie zbiorcze zamiast jednego rekordu na raz.


1

Niemal za każdym razem, gdy rozpoczynam nowy projekt, Google zadaje to samo pytanie, aby sprawdzić, czy znajdę jakieś nowe odpowiedzi.

Ostatecznie sprowadza się do - biorę najnowszą wersję MySQL i uruchamiam testy.

Mam tabele, w których chcę wyszukiwać klucze / wartości ... i to wszystko. Potrzebuję uzyskać wartość (0-512 bajtów) dla klucza skrótu. Na tym DB nie ma wielu transakcji. Tabela pobiera aktualizacje od czasu do czasu (w całości), ale 0 transakcji.

Więc nie mówimy tutaj o złożonym systemie, mówimy o prostym wyszukiwaniu, .. i jak (oprócz uczynienia rezydentnej pamięci RAM tabeli) możemy zoptymalizować wydajność.

Robię również testy na innych bazach danych (tj. NoSQL), aby sprawdzić, czy jest gdzieś, gdzie mogę uzyskać przewagę. Największą zaletą, jaką znalazłem, jest mapowanie kluczy, ale jeśli chodzi o wyszukiwanie, MyISAM aktualnie je przewyższa.

Chociaż nie przeprowadzałbym transakcji finansowych przy użyciu tabel MyISAM, ale dla prostych wyszukiwań powinieneś to przetestować. Zazwyczaj 2x do 5 razy więcej zapytań / sek.

Sprawdź to, z zadowoleniem przyjmuję debatę.


1

Jeśli jest to 70% wstawek i 30% odczytów, to bardziej przypomina to po stronie InnoDB.


0

dolna linia: jeśli pracujesz w trybie offline z zaznaczeniami na dużych porcjach danych, MyISAM prawdopodobnie da ci lepsze (znacznie lepsze) prędkości.

istnieją sytuacje, w których MyISAM jest nieskończenie bardziej wydajny niż InnoDB: podczas manipulowania dużymi zrzutami danych w trybie offline (z powodu blokady tabeli).

przykład: konwertowałem plik csv (15M rekordów) z NOAA, który używa pól VARCHAR jako kluczy. InnoDB trwało wiecznie, nawet przy dużej ilości dostępnej pamięci.

to jest przykład csv (pierwsze i trzecie pole to klucze).

USC00178998,20130101,TMAX,-22,,,7,0700
USC00178998,20130101,TMIN,-117,,,7,0700
USC00178998,20130101,TOBS,-28,,,7,0700
USC00178998,20130101,PRCP,0,T,,7,0700
USC00178998,20130101,SNOW,0,T,,7,

ponieważ muszę zrobić zbiorczą aktualizację offline obserwowanych zjawisk pogodowych, używam tabeli MyISAM do odbierania danych i uruchamiam JOINS na klawiszach, aby móc wyczyścić plik przychodzący i zastąpić pola VARCHAR kluczami INT (które są powiązane z tabele zewnętrzne, w których przechowywane są oryginalne wartości VARCHAR).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.