MyISAM versus InnoDB [geschlossen]

857

Ich arbeite an einem Projekt, das viele Datenbankschreibvorgänge umfasst ( 70% Einfügungen und 30% Lesevorgänge ). Dieses Verhältnis würde auch Aktualisierungen einschließen, die ich als ein Lese- und ein Schreibvorgang betrachte. Die Lesevorgänge können verschmutzt sein (z. B. benötige ich zum Zeitpunkt des Lesens keine 100% genauen Informationen).
Die fragliche Aufgabe besteht darin, mehr als 1 Million Datenbanktransaktionen pro Stunde durchzuführen.

Ich habe im Internet eine Reihe von Informationen über die Unterschiede zwischen MyISAM und InnoDB gelesen, und MyISAM scheint mir die offensichtliche Wahl für die bestimmte Datenbank / Tabelle zu sein, die ich für diese Aufgabe verwenden werde. Nach dem, was ich zu lesen scheine, ist InnoDB gut, wenn Transaktionen erforderlich sind, da das Sperren auf Zeilenebene unterstützt wird.

Hat jemand Erfahrung mit dieser Art von Last (oder höher)? Ist MyISAM der richtige Weg?

user2013
quelle
13
Der MySQL Performance Blog ist eine großartige Ressource für diese Art von Dingen.
Ceejayoz
3
Dies hängt ein wenig davon ab, ob Ihr System OLTP- oder mehr Datawarehouse-orientiert ist (wobei die meisten Schreibvorgänge Massenladevorgänge sind).
Nr.
35
MyISAM unterstützt keine Zeilensperrung, Transaktionen, es unterstützt nicht einmal Fremdschlüssel ... verdammt, da es keine ACID bereitstellen kann , kann es kaum als richtige Datenbank angesehen werden! Aus diesem Grund ist InnoDB seit MySQL 5.5 die Standard-Engine. Aus irgendeinem Grund ist MyISAM jedoch weiterhin die Standard-Engine für Tabellen, die in PhpMyAdmin erstellt wurden. Daher werden seitdem viele Amateurdatenbanken unter MyISAM ausgeführt.
BlueRaja - Danny Pflughoeft
finden Sie in diesem rackspace.com/knowledge_center/article/...
krishna

Antworten:

523

Ich habe diese Frage in einer Tabelle kurz besprochen, damit Sie entscheiden können, ob Sie sich für InnoDB oder MyISAM entscheiden .

Hier ist eine kleine Übersicht darüber, welche DB-Speicher-Engine Sie in welcher Situation verwenden sollten:

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
Erforderliche Volltextsuche Ja 5.6.4
-------------------------------------------------- --------------
Transaktionen erforderlich Ja
-------------------------------------------------- --------------
Häufige Auswahlabfragen Ja      
-------------------------------------------------- --------------
Häufiges Einfügen, Aktualisieren, Löschen Ja
-------------------------------------------------- --------------
Zeilensperrung (Mehrfachverarbeitung für eine einzelne Tabelle) Ja
-------------------------------------------------- --------------
Relationales Basisdesign Ja

Zusammenfassung

  • InnoDB ist unter fast allen Umständen der beste Weg
  • Verwenden Sie MyISAM jedoch , wenn Sie häufig lesen und fast nicht schreiben
  • Verwenden Sie bei der Volltextsuche in MySQL <= 5.5 MyISAM
Entwickler99
quelle
11
InnoDB verfügt über Volltextindizes in MySQL 5.6, die jedoch noch nicht für den produktiven Einsatz bereit sind.
Bill Karwin
3
Gemäß 12.9. Volltextsuchfunktionen „Volltextindizes können nur mit InnoDB- oder MyISAM-Tabellen verwendet werden“. Scheint für MySQL> = 5.6 in Ordnung zu sein, auf derselben Seite für MySQL 5.5 steht jedoch weiterhin "Volltextindizes können nur mit MyISAM-Tabellen verwendet werden". Die obige Tabelle könnte aktualisiert werden, um zu zeigen, wie sie sich von MySQL-Versionen unterscheidet. Leider scheint MySQL 5.5 bisher der Standard zu sein.
Hibou57
2
Was bedeutet: InnoDB - full-text: 5.6.4?? Es ist ja oder nicht?
2
MyISAM speichert die Zeilenanzahl auch intern. Daher ist die Count () - Funktion in MyISAM fast kostenlos, während sie in InnoDB spürbar viel Zeit in Anspruch nimmt.
Hedeshy
3
Gute Tabelle, aber eine Zeile für Qualität und Stabilität hinzufügen, MyIsam = nein, innoDB = ja würde es noch besser machen
pilavdzice
268

Ich bin kein Datenbankexperte und spreche nicht aus Erfahrung. Jedoch:

MyISAM-Tabellen verwenden Sperren auf Tabellenebene . Basierend auf Ihren Verkehrsschätzungen haben Sie fast 200 Schreibvorgänge pro Sekunde. Mit MyISAM kann immer nur eine davon ausgeführt werden . Sie müssen sicherstellen, dass Ihre Hardware mit diesen Transaktionen Schritt halten kann, um ein Überlaufen zu vermeiden. Das heißt, eine einzelne Abfrage kann nicht länger als 5 ms dauern.

Das legt für mich nahe, dass Sie eine Speicher-Engine benötigen, die das Sperren auf Zeilenebene unterstützt, dh InnoDB.

Auf der anderen Seite sollte es ziemlich trivial sein, ein paar einfache Skripte zu schreiben, um die Last mit jeder Speicher-Engine zu simulieren, und dann die Ergebnisse zu vergleichen.

rix0rrr
quelle
12
Fast 200? Wenn seine durchschnittliche Transaktion 2,5 Abfragen macht, ist das [(2,5 * 1M) / 3600s =] näher an 700.
Ozzy
12
Ich bin auch anderer Meinung, a single query can take no more than 5msweil Sie zwei unwahrscheinliche Annahmen gemacht haben; A: Alle Abfragen benötigten dieselbe Tabelle & B: Es war nur 1 Verbindung verfügbar! Ich sollte Sie darüber informieren, dass ein Linux- und MySQL 5.5-Setup mit hohem RAM bis zu 10.000 gleichzeitige Verbindungen unterstützen kann (siehe: dev.mysql.com/doc/refman//5.5/en/too-many-connections.html ).
Ozzy
152
Wenn eine Tabelle tabellensperrend ist, kann jeweils nur eine Abfrage ausgeführt werden. Es spielt keine Rolle, ob der Server 10000 gleichzeitige Verbindungen unterstützt. Jede Verbindung wird gesichert, während die Tabelle gesperrt ist.
Ryaner
2
Es kann auch hilfreich sein zu wissen, dass MyISAM den räumlichen Index unterstützt, InnoDB jedoch nicht. Und MyISAM scheint keine Fremdschlüssel zu verwenden, obwohl dies die Erstellung eines Schlüssels nicht verhindert.
Kriver
4
@kriver: Sie können keine Fremdschlüssel in MyISAM-Tabellen haben. Sie können FK-Definitionen in die CREATE TABLE-Anweisungen aufnehmen, diese (die Definitionen) werden jedoch einfach ignoriert.
Ypercubeᵀᴹ
191

Die Leute reden oft über Leistung, Lesen gegen Schreiben, Fremdschlüssel usw., aber meiner Meinung nach gibt es noch eine andere unverzichtbare Funktion für eine Speicher-Engine: atomare Updates.

Versuche dies:

  1. Stellen Sie ein UPDATE für Ihre MyISAM-Tabelle aus, das 5 Sekunden dauert.
  2. Während das UPDATE ausgeführt wird, z. B. 2,5 Sekunden, drücken Sie Strg-C, um es zu unterbrechen.
  3. Beobachten Sie die Auswirkungen auf den Tisch. Wie viele Zeilen wurden aktualisiert? Wie viele wurden nicht aktualisiert? Ist die Tabelle überhaupt lesbar oder wurde sie beschädigt, als Sie Strg-C gedrückt haben?
  4. Versuchen Sie dasselbe Experiment mit UPDATE für eine InnoDB-Tabelle und unterbrechen Sie die laufende Abfrage.
  5. Beachten Sie die InnoDB-Tabelle. Nullzeilen wurden aktualisiert. InnoDB hat versichert, dass Sie über atomare Updates verfügen. Wenn das vollständige Update nicht festgeschrieben werden konnte, wird die gesamte Änderung rückgängig gemacht. Außerdem ist die Tabelle nicht beschädigt. Dies funktioniert auch dann, wenn Sie killall -9 mysqldeinen Absturz simulieren.

Leistung ist natürlich wünschenswert, aber kein Datenverlust sollte das übertreffen.

Bill Karwin
quelle
4
Für den Datensatz werden die anderen Merkmale einer ACID-Datenbank - Konsistenz, Isolation und Haltbarkeit - von MyISAM ebenfalls nicht unterstützt.
Bill Karwin
Control-C sollte die Tabelle nicht beschädigen - wie in CHECK TABLE wird der Erfolg zurückgegeben und alle Abfragen werden ohne Fehler fortgesetzt. MyISAM bricht die Aktualisierung ab, ohne alle Datensätze zu aktualisieren, aber die Tabelle behält die interne strukturelle Integrität bei. Das Töten von mysqld mit SIGTERM hat den gleichen Effekt. Wenn Sie ihm jedoch SIGKILL (kill -9) oder ein Absturzsignal geben (oder es sich selbst verdienen, wenn es auf einen Fehler trifft) oder wenn das Betriebssystem abstürzt / die Stromversorgung verloren geht, ist es eine andere Geschichte - Sie können sehen Korruption auf MyISAM-Ebene.
Sasha Pachev
1
InnoDB kann sich auch königlich verderben, normalerweise königlicher als MyISAM, wenn dies der Fall ist. Die Ironie von ACID ist, dass wir die Vorstellung von allem oder nichts haben. Wenn InnoDB also nicht alles geben kann, gibt es nichts - interne Zusicherung, und es weigert sich, überhaupt zu laufen, weil ein Byte in einer Struktur falsch ist - 90% der Zeit hätte es ignoriert werden können und es würde höchstens nur eine Tabelle betreffen. Neuere Percona-Server haben die Möglichkeit, damit umzugehen - innodb_pass_corrupt_table.
Sasha Pachev
1
Ich habe diese Art von Informationen aus den letzten 3 Tagen gesucht, jetzt habe ich diese. InnoDB ist am besten. Vielen DankBill Karwin
user3833682
3
@ flow2k, heutzutage fast keine. Bei meinem letzten Job haben wir MyISAM für eine Tabelle auf einem Server verwendet, und der einzige Grund war, dass MyISAM diese bestimmte Tabelle auf weniger Speicherplatz speichern konnte als InnoDB. Der Speicherplatz war begrenzt, daher mussten wir MyISAM verwenden, bis wir die Datenbank auf einen anderen Server verschieben konnten. Bei meinem neuen Job gibt es bereits eine Richtlinie, dass jede Tabelle InnoDB sein muss.
Bill Karwin
138

Ich habe mit MySQL an einem hochvolumigen System gearbeitet und sowohl MyISAM als auch InnoDB ausprobiert.

Ich habe festgestellt, dass das Sperren auf Tabellenebene in MyISAM schwerwiegende Leistungsprobleme für unsere Arbeitslast verursacht hat, die sich ähnlich anhören wie Ihre. Leider stellte ich auch fest, dass die Leistung unter InnoDB auch schlechter war als ich gehofft hatte.

Am Ende habe ich das Konfliktproblem gelöst, indem ich die Daten so fragmentiert habe, dass Einfügungen in eine "heiße" Tabelle verschoben wurden und die Auswahl nie abgefragt wurde.

Dies ermöglichte auch das Löschen (die Daten waren zeitkritisch und wir haben nur den Wert von X Tagen beibehalten) in "veralteten" Tabellen, die wiederum nicht von ausgewählten Abfragen berührt wurden. InnoDB scheint bei Massenlöschvorgängen eine schlechte Leistung zu haben. Wenn Sie also Daten löschen möchten, möchten Sie diese möglicherweise so strukturieren, dass sich die alten Daten in einer veralteten Tabelle befinden, die einfach gelöscht werden kann, anstatt Löschvorgänge auszuführen.

Natürlich habe ich keine Ahnung, was Ihre Anwendung ist, aber hoffentlich gibt Ihnen dies einen Einblick in einige der Probleme mit MyISAM und InnoDB.

alanc10n
quelle
3
"Am Ende habe ich das Konfliktproblem gelöst, indem ich die Daten so fragmentiert habe, dass Einfügungen in eine" heiße "Tabelle gingen und die Auswahl nie abgefragt wurde."
Ist das
15
Danny - Nein, nicht wirklich. Das Optimieren der Servereinstellungen ist wichtig, aber keinesfalls ein Ersatz für eine sorgfältige Strukturierung Ihres Schemas. Wenn Sie eine Datenbank haben, die viel, viel größer als der verfügbare RAM ist, und auf Zugriffsmuster zugreifen, die Daten in der gesamten Datenbank zufällig berühren, hilft Ihnen die gesamte Optimierung des Pufferpools in der Welt nicht weiter. Wenn Sie die Daten und die Zugriffsmuster verstehen, können Sie durch sorgfältiges Design einen Großteil der Schmerzen lindern.
Alanc10n
66

Ein bisschen spät zum Spiel ... aber hier ist ein ziemlich umfassender Beitrag, den ich vor einigen Monaten geschrieben habe und in dem die Hauptunterschiede zwischen MYISAM und InnoDB beschrieben werden. Nehmen Sie eine Tasse Kaffee (und vielleicht einen Keks) und genießen Sie.


Der Hauptunterschied zwischen MyISAM und InnoDB besteht in der referenziellen Integrität und den Transaktionen. Es gibt auch andere Unterschiede wie Sperren, Rollbacks und Volltextsuche.

Referenzielle Integrität

Die referenzielle Integrität stellt sicher, dass die Beziehungen zwischen Tabellen konsistent bleiben. Insbesondere bedeutet dies, dass wenn eine Tabelle (z. B. Auflistungen) einen Fremdschlüssel (z. B. Produkt-ID) hat, der auf eine andere Tabelle (z. B. Produkte) verweist, wenn Aktualisierungen oder Löschungen der Tabelle vorgenommen werden, auf die verwiesen wird, diese Änderungen an die Verknüpfung kaskadiert werden Tabelle. In unserem Beispiel werden beim Umbenennen eines Produkts auch die Fremdschlüssel der Verknüpfungstabelle aktualisiert. Wenn ein Produkt aus der Tabelle "Produkte" gelöscht wird, werden auch alle Einträge gelöscht, die auf den gelöschten Eintrag verweisen. Darüber hinaus muss in jeder neuen Liste dieser Fremdschlüssel auf einen gültigen, vorhandenen Eintrag verweisen.

InnoDB ist ein relationales DBMS (RDBMS) und weist daher eine referenzielle Integrität auf, MyISAM jedoch nicht.

Transaktionen & Atomizität

Daten in einer Tabelle werden mit DML-Anweisungen (Data Manipulation Language) wie SELECT, INSERT, UPDATE und DELETE verwaltet. Eine Transaktionsgruppe zwei oder mehr DML-Anweisungen zu einer einzigen Arbeitseinheit, sodass entweder die gesamte Einheit angewendet wird oder keine davon.

MyISAM unterstützt keine Transaktionen, InnoDB jedoch nicht.

Wenn eine Operation während der Verwendung einer MyISAM-Tabelle unterbrochen wird, wird die Operation sofort abgebrochen, und die betroffenen Zeilen (oder sogar Daten in jeder Zeile) bleiben betroffen, auch wenn die Operation nicht abgeschlossen wurde.

Wenn eine Operation während der Verwendung einer InnoDB-Tabelle unterbrochen wird, weil sie Transaktionen mit Atomizität verwendet, wird jede Transaktion, die nicht abgeschlossen wurde, nicht wirksam, da keine Festschreibung erfolgt.

Tabellensperre vs Zeilensperre

Wenn eine Abfrage für eine MyISAM-Tabelle ausgeführt wird, wird die gesamte Tabelle, in der sie abgefragt wird, gesperrt. Dies bedeutet, dass nachfolgende Abfragen erst ausgeführt werden, nachdem die aktuelle abgeschlossen ist. Wenn Sie eine große Tabelle lesen und / oder häufig Lese- und Schreibvorgänge ausgeführt werden, kann dies einen großen Rückstau an Abfragen bedeuten.

Wenn eine Abfrage für eine InnoDB-Tabelle ausgeführt wird, sind nur die betroffenen Zeilen gesperrt. Der Rest der Tabelle bleibt für CRUD-Operationen verfügbar. Dies bedeutet, dass Abfragen gleichzeitig in derselben Tabelle ausgeführt werden können, sofern sie nicht dieselbe Zeile verwenden.

Diese Funktion in InnoDB wird als Parallelität bezeichnet. So groß die Parallelität auch ist, es gibt einen großen Nachteil, der für einen ausgewählten Tabellenbereich gilt, da das Umschalten zwischen Kernel-Threads einen Mehraufwand verursacht und Sie ein Limit für die Kernel-Threads festlegen sollten, um zu verhindern, dass der Server zum Stillstand kommt .

Transaktionen & Rollbacks

Wenn Sie eine Operation in MyISAM ausführen, werden die Änderungen festgelegt. In InnoDB können diese Änderungen rückgängig gemacht werden. Die am häufigsten zur Steuerung von Transaktionen verwendeten Befehle sind COMMIT, ROLLBACK und SAVEPOINT. 1. COMMIT - Sie können mehrere DML-Vorgänge schreiben, die Änderungen werden jedoch nur gespeichert, wenn ein COMMIT durchgeführt wird. 2. ROLLBACK - Sie können alle noch nicht festgeschriebenen Vorgänge verwerfen. 3. SAVEPOINT - Setzt einen Punkt in der Liste von Operationen, auf die eine ROLLBACK-Operation zurückgesetzt werden kann

Verlässlichkeit

MyISAM bietet keine Datenintegrität - Hardwarefehler, unsauberes Herunterfahren und abgebrochene Vorgänge können dazu führen, dass die Daten beschädigt werden. Dies würde eine vollständige Reparatur oder Neuerstellung der Indizes und Tabellen erfordern.

InnoDB verwendet dagegen ein Transaktionsprotokoll, einen Doppelschreibpuffer sowie eine automatische Prüfsumme und Validierung, um Beschädigungen zu vermeiden. Bevor InnoDB Änderungen vornimmt, zeichnet es die Daten vor den Transaktionen in einer Systemtabellenbereichsdatei mit dem Namen ibdata1 auf. Im Falle eines Absturzes würde InnoDB die Wiedergabe dieser Protokolle automatisch wiederherstellen.

FULLTEXT-Indizierung

InnoDB unterstützt die FULLTEXT-Indizierung erst in MySQL Version 5.6.4. Zum Zeitpunkt des Schreibens dieses Beitrags liegt die MySQL-Version vieler Shared Hosting-Anbieter immer noch unter 5.6.4, was bedeutet, dass die FULLTEXT-Indizierung für InnoDB-Tabellen nicht unterstützt wird.

Dies ist jedoch kein gültiger Grund für die Verwendung von MyISAM. Wechseln Sie am besten zu einem Hosting-Anbieter, der aktuelle Versionen von MySQL unterstützt. Nicht dass eine MyISAM-Tabelle, die die FULLTEXT-Indizierung verwendet, nicht in eine InnoDB-Tabelle konvertiert werden kann.

Fazit

Zusammenfassend sollte InnoDB Ihre Standardspeicher-Engine Ihrer Wahl sein. Wählen Sie MyISAM oder andere Datentypen, wenn diese einem bestimmten Bedarf entsprechen.

d4nyll
quelle
Ich habe ein PHP-Session-Prüfsummenskript erstellt und die meisten meiner Schlüssel sind zufällige Zeichenfolgen von [az09] ... Innodb hat über 30 ms gebraucht, um dies zu tun, INSERT ON DUPLICATE KEY UPDATEalso habe ich MyISAM ausprobiert und jetzt sind es nur noch <1 ms ... Viele Antworten, die ich gesehen habe, sagen das innodb fällt es schwer, mit 'unsortierbaren' (zufälligen Zeichenfolgen) eindeutigen Schlüsseln umzugehen ... Haben Sie dazu irgendwelche Eingaben für uns? Tatsächlich habe ich mich gefragt, welche Auswirkungen MyISAM haben würde, aber Ihre großartige Antwort hat mir klar gemacht, dass dies der richtige Weg für diesen speziellen Fall ist.
Louis Loudog Trottier
64

Für eine Last mit mehr Schreib- und Lesevorgängen profitieren Sie von InnoDB. Da InnoDB eher Zeilen- als Tabellensperren bietet, können Ihre SELECTs nicht nur untereinander, sondern auch mit vielen INSERTs gleichzeitig ausgeführt werden. Wenn Sie jedoch nicht beabsichtigen, SQL-Transaktionen zu verwenden, setzen Sie den InnoDB-Commit-Flush auf 2 ( innodb_flush_log_at_trx_commit ). Dies gibt Ihnen eine Menge Rohleistung zurück, die Sie sonst verlieren würden, wenn Sie Tabellen von MyISAM nach InnoDB verschieben.

Erwägen Sie auch das Hinzufügen einer Replikation. Auf diese Weise erhalten Sie eine gewisse Leseskalierung. Da Sie angegeben haben, dass Ihre Lesevorgänge nicht auf dem neuesten Stand sein müssen, können Sie die Replikation etwas zurückfallen lassen. Stellen Sie nur sicher, dass es unter nichts anderem als dem stärksten Verkehr aufholen kann, oder es wird immer zurückbleiben und niemals aufholen. Wenn Sie diesen Weg gehen, empfehle ich Ihnen dringend , das Lesen von den Slaves und die Verwaltung der Replikationsverzögerung auf Ihren Datenbankhandler zu beschränken. Es ist so viel einfacher, wenn der Anwendungscode nichts davon weiß.

Beachten Sie schließlich die unterschiedlichen Tischlasten. Sie haben nicht für alle Tabellen das gleiche Lese- / Schreibverhältnis. Einige kleinere Tabellen mit nahezu 100% Lesevorgängen könnten es sich leisten, MyISAM zu bleiben. Wenn Sie einige Tabellen haben, die fast zu 100% geschrieben sind, können Sie davon profitieren INSERT DELAYED, dies wird jedoch nur in MyISAM unterstützt (die DELAYEDKlausel wird für eine InnoDB-Tabelle ignoriert).

Aber Benchmark um sicher zu sein.

staticsan
quelle
4
Ist das "InnoDB Commit Flush", auf das Sie sich beziehen innodb_flush_log_at_trx_commit?
Ceejayoz
2
Ich fand Ihren Beitrag sehr nützlich - danke. Derzeit war es hilfreich zu prüfen, wann MyISAM / InnoDB für meine Tabellen verwendet werden soll, und Ihr Beitrag war hilfreich. Prost.
Starmonkey
2
dev.mysql.com/doc/refman/5.5/en/insert-delayed.html gibt Folgendes an: Wenn in MyISAM-Tabellen keine freien Blöcke in der Mitte der Datendatei vorhanden sind, werden gleichzeitige SELECT- und INSERT-Anweisungen unterstützt. Unter diesen Umständen müssen Sie INSERT DELAYED nur sehr selten mit MyISAM verwenden.
Tymtam
Sehr informativer Beitrag. Ich hatte die gleiche Frage wie die OP und ich muss sagen, dass Ihr Beitrag mich bei meiner Entscheidung über die Datenbank-Engine beruhigt hat. Vielen Dank! ++
Joe Majewski
Kurzer Hinweis: Verspätet wird in 5.7 nicht mehr unterstützt. Möglicherweise möchten Sie stattdessen mit LOW_PRIORITY testen.
Webmat
59

Um die große Auswahl an Antworten zu ergänzen, die die mechanischen Unterschiede zwischen den beiden Motoren abdecken, präsentiere ich eine empirische Geschwindigkeitsvergleichsstudie.

In Bezug auf die reine Geschwindigkeit ist MyISAM nicht immer schneller als InnoDB, aber meiner Erfahrung nach ist es für PURE READ-Arbeitsumgebungen tendenziell um das 2,0- bis 2,5-fache schneller. Dies ist natürlich nicht für alle Umgebungen geeignet. Wie andere bereits geschrieben haben, fehlen MyISAM beispielsweise Transaktionen und Fremdschlüssel.

Ich habe unten ein bisschen Benchmarking durchgeführt - ich habe Python für Loops und die Timeit-Bibliothek für Timing-Vergleiche verwendet. Aus Interesse habe ich auch die Speicher-Engine aufgenommen, die auf der ganzen Linie die beste Leistung bietet, obwohl sie nur für kleinere Tabellen geeignet ist ( The table 'tbl' is fullwenn Sie das MySQL-Speicherlimit überschreiten, treten Sie ständig auf ). Die vier Arten von Auswahl, die ich betrachte, sind:

  1. Vanille SELECTs
  2. zählt
  3. bedingte SELECTs
  4. indizierte und nicht indizierte Unterauswahlen

Zuerst habe ich drei Tabellen mit dem folgenden SQL erstellt

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

In der zweiten und dritten Tabelle wird "InnoDB" und "Speicher" durch "MyISAM" ersetzt.

 

1) Vanille wählt aus

Abfrage: SELECT * FROM tbl WHERE index_col = xx

Ergebnis: Unentschieden

Vergleich der Vanille-Auswahl durch verschiedene Datenbank-Engines

Die Geschwindigkeit dieser ist im Großen und Ganzen gleich und wie erwartet linear in der Anzahl der auszuwählenden Spalten. InnoDB scheint etwas schneller als MyISAM zu sein, aber das ist wirklich marginal.

Code:

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) Zählt

Abfrage: SELECT count(*) FROM tbl

Ergebnis: MyISAM gewinnt

Vergleich der Anzahl durch verschiedene Datenbank-Engines

Dieser zeigt einen großen Unterschied zwischen MyISAM und InnoDB - MyISAM (und Speicher) verfolgt die Anzahl der Datensätze in der Tabelle, sodass diese Transaktion schnell und O (1) ist. Die Zeit, die InnoDB zum Zählen benötigt, steigt mit der Tabellengröße in dem von mir untersuchten Bereich superlinear an. Ich vermute, dass viele der in der Praxis beobachteten Beschleunigungen durch MyISAM-Abfragen auf ähnliche Effekte zurückzuführen sind.

Code:

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) Bedingte Auswahl

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

Ergebnis: MyISAM gewinnt

Vergleich der bedingten Auswahl durch verschiedene Datenbankmodule

Hier arbeiten MyISAM und Speicher ungefähr gleich und übertreffen InnoDB bei größeren Tabellen um etwa 50%. Dies ist die Art von Abfrage, für die die Vorteile von MyISAM maximiert zu sein scheinen.

Code:

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) Unterauswahl

Ergebnis: InnoDB gewinnt

Für diese Abfrage habe ich einen zusätzlichen Satz von Tabellen für die Unterauswahl erstellt. Jede besteht einfach aus zwei Spalten von BIGINTs, eine mit einem Primärschlüsselindex und eine ohne Index. Aufgrund der großen Tabellengröße habe ich die Speicher-Engine nicht getestet. Der Befehl zum Erstellen einer SQL-Tabelle war

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

In der zweiten Tabelle wird 'InnoDB' durch 'MyISAM' ersetzt.

In dieser Abfrage belasse ich die Größe der Auswahltabelle bei 1000000 und variiere stattdessen die Größe der unterausgewählten Spalten.

Vergleich von Unterauswahlen durch verschiedene Datenbankmodule

Hier gewinnt die InnoDB leicht. Nachdem wir eine vernünftige Größentabelle erreicht haben, skalieren beide Motoren linear mit der Größe der Unterauswahl. Der Index beschleunigt den MyISAM-Befehl, hat jedoch interessanterweise wenig Einfluss auf die InnoDB-Geschwindigkeit. subSelect.png

Code:

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) )

Ich denke, die Botschaft zum Mitnehmen ist, dass Sie, wenn Sie sich wirklich Gedanken über die Geschwindigkeit machen, die von Ihnen durchgeführten Abfragen vergleichen müssen, anstatt Annahmen darüber zu treffen, welche Engine besser geeignet ist.

StackG
quelle
1
Leistung ist nicht immer die einzige Überlegung. Wie wäre es mit einem Diagramm über Stabilität? Eine Engine ist für nichts gut, wenn sie abstürzt und keine grundlegenden Datenbankfunktionen unterstützt.
Pilavdzice
1
MyISAM würde InnoDB wahrscheinlich die meiste Zeit schlagen, wenn die my.cnfDatei nicht für InnoDB optimiert ist. Sie haben nicht erwähnt, wie Ihre my.cnfDatei aussieht, was wirklich der wichtigste Faktor für die Leistung von InnoDB ist.
Itoctopus
Danke itoctopus - Ich würde gerne mehr über die von Ihnen empfohlenen Optimierungen erfahren. Der vollständige Code, der in diesen Tests verwendet wird, befindet sich oben. Sie können die Experimente mit verschiedenen Optimierungen wiederholen und uns
mitteilen
32

Etwas abseits des Themas, aber zu Dokumentationszwecken und zur Vollständigkeit möchte ich Folgendes hinzufügen.

Im Allgemeinen führt die Verwendung von InnoDB zu einer viel WENIGER komplexen Anwendung, die wahrscheinlich auch fehlerfreier ist. Da Sie die gesamte referenzielle Integrität (Fremdschlüsseleinschränkungen) in das Datenmodell einfügen können, benötigen Sie nicht annähernd so viel Anwendungscode, wie Sie mit MyISAM benötigen.

Jedes Mal, wenn Sie einen Datensatz einfügen, löschen oder ersetzen, MÜSSEN Sie die Beziehungen überprüfen und pflegen. Wenn Sie beispielsweise ein Elternteil löschen, sollten auch alle Kinder gelöscht werden. Selbst in einem einfachen Blogging-System müssen Sie beispielsweise beim Löschen eines Blogposting-Datensatzes die Kommentardatensätze, Likes usw. löschen. In InnoDB erfolgt dies automatisch durch das Datenbankmodul (wenn Sie die Einschränkungen im Modell angegeben haben ) und erfordert keinen Anwendungscode. In MyISAM muss dies in die Anwendung codiert werden, was auf Webservern sehr schwierig ist. Webserver sind von Natur aus sehr gleichzeitig / parallel. Da diese Aktionen atomar sein sollten und MyISAM keine echten Transaktionen unterstützt, ist die Verwendung von MyISAM für Webserver riskant / fehleranfällig.

Auch in den meisten allgemeinen Fällen wird InnoDB aus mehreren Gründen eine viel bessere Leistung erbringen, da sie in der Lage sind, Sperren auf Datensatzebene im Gegensatz zu Sperren auf Tabellenebene zu verwenden. Nicht nur in Situationen, in denen Schreibvorgänge häufiger sind als Lesevorgänge, sondern auch in Situationen mit komplexen Verknüpfungen in großen Datenmengen. Wir haben eine dreifache Leistungssteigerung festgestellt, indem wir InnoDB-Tabellen gegenüber MyISAM-Tabellen für sehr große Verknüpfungen verwendet haben (dies dauert einige Minuten).

Ich würde sagen, dass InnoDB (unter Verwendung eines 3NF-Datenmodells mit referenzieller Integrität) im Allgemeinen die Standardauswahl bei der Verwendung von MySQL sein sollte. MyISAM sollte nur in ganz bestimmten Fällen verwendet werden. Es wird höchstwahrscheinlich weniger Leistung bringen, was zu einer größeren und fehlerhafteren Anwendung führt.

Nachdem ich das gesagt habe. Datamodelling ist eine Kunst, die unter Webdesignern / -programmierern selten zu finden ist. Nichts für ungut, aber es erklärt, dass MyISAM so oft verwendet wird.

Patrick Savalle
quelle
31

InnoDB bietet:

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

In InnoDB können alle Daten in einer Reihe mit Ausnahme von TEXT und BLOB höchstens 8.000 Byte belegen. Für InnoDB ist keine Volltextindizierung verfügbar. In InnoDB werden die COUNT (*) s (wenn WHERE, GROUP BY oder JOIN nicht verwendet werden) langsamer ausgeführt als in MyISAM, da die Zeilenanzahl nicht intern gespeichert wird. InnoDB speichert sowohl Daten als auch Indizes in einer Datei. InnoDB verwendet einen Pufferpool, um sowohl Daten als auch Indizes zwischenzuspeichern.

MyISAM bietet:

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 verfügt über eine Sperre auf Tabellenebene, jedoch keine Sperre auf Zeilenebene. Keine Transaktionen. Keine automatische Wiederherstellung nach einem Absturz, bietet jedoch Funktionen für Reparaturtabellen. Keine Fremdschlüsseleinschränkungen. MyISAM-Tabellen sind im Vergleich zu InnoDB-Tabellen im Allgemeinen kompakter auf der Festplatte. MyISAM-Tabellen können durch Komprimieren mit myisampack bei Bedarf weiter verkleinert werden, sind jedoch schreibgeschützt. MyISAM speichert Indizes in einer Datei und Daten in einer anderen. MyISAM verwendet Schlüsselpuffer zum Zwischenspeichern von Indizes und überlässt die Verwaltung des Daten-Zwischenspeicherns dem Betriebssystem.

Insgesamt würde ich InnoDB für die meisten Zwecke und MyISAM nur für spezielle Zwecke empfehlen. InnoDB ist jetzt die Standard-Engine in neuen MySQL-Versionen.

Pankaj Khurana
quelle
2
fwiw, VARCHAR in InnoDB kann auch zu Überlaufseiten wechseln, wie dies bei BLOB und TEXT der Fall ist. Alle diese Datentypen werden ähnlich intern gespeichert.
Bill Karwin
Gut zu wissen, @BillKarwin! Wir verwenden VARCHAR in unserer App stark und es war ein wenig besorgniserregend, dass VARCHAR zu diesem ~ 8-kB-Limit beitrug.
Rinogo
Die Antwort ist nicht mehr aktuell, da die Innodb-Engine in MySQL Version 5.6+ heutzutage auch die Volltextindizierung unterstützt und auch MySQL 5.5 + / 5.7 + räumliche Datentypen (5.5+) und räumliche Indizes (r-tee) (5.7+) unterstützt. .. Für die beste Unterstützung benötigen Sie mindestens MySQL Version 5.7+
Raymond Nijland
25

Wenn Sie MyISAM verwenden, werden Sie keine Transaktionen pro Stunde ausführen, es sei denn, Sie betrachten jede DML-Anweisung als eine Transaktion (die im Falle eines Absturzes auf keinen Fall dauerhaft oder atomar ist).

Daher denke ich, dass Sie InnoDB verwenden müssen.

300 Transaktionen pro Sekunde klingen nach ziemlich viel. Wenn Sie diese Transaktionen unbedingt benötigen, um bei Stromausfall dauerhaft zu sein, stellen Sie sicher, dass Ihr E / A-Subsystem so viele Schreibvorgänge pro Sekunde problemlos verarbeiten kann. Sie benötigen mindestens einen RAID-Controller mit batteriegepuffertem Cache.

Wenn Sie einen kleinen Haltbarkeitstreffer erzielen können, können Sie InnoDB verwenden, wobei innodb_flush_log_at_trx_commit auf 0 oder 2 gesetzt ist (Details finden Sie in den Dokumenten). Sie können die Leistung verbessern.

Es gibt eine Reihe von Patches, die die Parallelität von Google und anderen erhöhen können. Diese können von Interesse sein, wenn Sie ohne sie immer noch nicht genügend Leistung erzielen können.

MarkR
quelle
24

Die Frage und die meisten Antworten sind veraltet .

Ja, es ist eine Geschichte alter Frauen, dass MyISAM schneller als InnoDB ist. Beachten Sie das Datum der Frage: 2008; es ist jetzt fast ein Jahrzehnt später. InnoDB hat seitdem erhebliche Leistungsschritte gemacht.

Die dramatische Graph war für den einen Fall , in dem MyISAM gewinnt: COUNT(*) ohne eine WHEREKlausel. Aber verbringst du deine Zeit wirklich damit?

Wenn Sie einen Parallelitätstest durchführen, ist es sehr wahrscheinlich, dass InnoDB gewinnt, auch gegenMEMORY .

Wenn Sie während des Benchmarking Schreibvorgänge SELECTsausführen MEMORY, verlieren MyISAM und wahrscheinlich aufgrund von Sperren auf Tabellenebene.

Tatsächlich ist Oracle sich so sicher, dass InnoDB besser ist, als dass MyISAM von 8.0 so gut wie entfernt wurde.

Die Frage wurde früh in den Tagen von 5.1 geschrieben. Seitdem wurden diese Hauptversionen als "Allgemeine Verfügbarkeit" gekennzeichnet:

  • 2010: 5,5 (0,8 im Dezember)
  • 2013: 5,6 (.10 im Februar)
  • 2015: 5,7 (0,9 im Oktober)
  • 2018: 8,0 (.11 im April)

Fazit: Verwenden Sie MyISAM nicht

Rick James
quelle
2
Fortschritte in der MySQL-Datenbanktechnologie. Und die Fragen und Antworten von StackOverflow sind in der Vergangenheit festgefahren. Die Hauptunterschiede zwischen MyISAM und InnoDB betreffen weniger die "Auslastung" des Servers als vielmehr die Unterstützung der referenziellen Integrität und Transaktionen sowie die Parallelität und Wiederherstellbarkeit (+10)
spencer7593
12

Schauen Sie sich auch einige Drop-In-Ersetzungen für MySQL selbst an:

MariaDB

http://mariadb.org/

MariaDB ist ein Datenbankserver, der Drop-In-Ersatzfunktionen für MySQL bietet. MariaDB wurde von einigen der ursprünglichen Autoren von MySQL mit Unterstützung der breiteren Community von Entwicklern von Free- und Open-Source-Software erstellt. Zusätzlich zu den Kernfunktionen von MySQL bietet MariaDB eine Reihe von Funktionserweiterungen, darunter alternative Speicher-Engines, Serveroptimierungen und Patches.

Percona Server

https://launchpad.net/percona-server

Ein erweiterter Drop-In-Ersatz für MySQL mit besserer Leistung, verbesserter Diagnose und zusätzlichen Funktionen.

Refiner
quelle
1
Ich benutze beide (Percona in der Produktion, Maria in der Windows-Entwicklung). Sie sind schneller und arbeiten perfekt.
Moshe L
4
Dies beantwortet die Frage nicht. MariaDB und Percona sind Gabeln von MySQL und verwenden auch InnoDB- und MyISAM-Engines.
dr_
12

Bitte beachten Sie, dass meine formale Ausbildung und Erfahrung bei Oracle liegt, während meine Arbeit mit MySQL ganz persönlich und in meiner Freizeit war. Wenn ich also Dinge sage, die für Oracle gelten, für MySQL jedoch nicht, entschuldige ich mich. Während die beiden Systeme viel gemeinsam haben, ist die relationale Theorie / Algebra dieselbe und relationale Datenbanken sind immer noch relationale Datenbanken, es gibt immer noch viele Unterschiede !!

Ich mag besonders (sowie das Sperren auf Zeilenebene), dass InnoDB transaktionsbasiert ist, was bedeutet, dass Sie möglicherweise mehrmals für einen "Vorgang" Ihrer Webanwendung aktualisieren / einfügen / erstellen / ändern / löschen / usw. Das Problem besteht darin, dass Sie, wenn nur einige dieser Änderungen / Vorgänge festgeschrieben werden, andere jedoch nicht (abhängig vom spezifischen Design der Datenbank), meistens eine Datenbank mit widersprüchlichen Daten / Strukturen erhalten.

Hinweis: Bei Oracle werden create / alter / drop-Anweisungen als "DDL" -Anweisungen (Data Definition) bezeichnet und lösen implizit ein Commit aus. Anweisungen zum Einfügen / Aktualisieren / Löschen mit der Bezeichnung "DML" (Data Manipulation) werden nicht automatisch festgeschrieben, sondern nur, wenn eine DDL, ein Festschreiben oder ein Beenden / Beenden ausgeführt wird (oder wenn Sie Ihre Sitzung auf "Auto-Commit" setzen oder wenn Ihr Client automatisch festschreibt). Wenn Sie mit Oracle arbeiten, müssen Sie sich dessen unbedingt bewusst sein, aber ich bin mir nicht sicher, wie MySQL mit den beiden Arten von Anweisungen umgeht. Aus diesem Grund möchte ich klarstellen, dass ich mir bei MySQL nicht sicher bin. nur mit Oracle.

Ein Beispiel dafür, wann transaktionsbasierte Engines sich auszeichnen:

Nehmen wir an, ich oder Sie befinden sich auf einer Webseite, um sich für eine kostenlose Veranstaltung anzumelden. Einer der Hauptzwecke des Systems besteht darin, nur bis zu 100 Personen die Anmeldung zu ermöglichen, da dies die Begrenzung der Sitzplätze darstellt Für das Event. Sobald 100 Anmeldungen erreicht sind, würde das System weitere Anmeldungen deaktivieren, zumindest bis andere abbrechen.

In diesem Fall gibt es möglicherweise einen Tisch für Gäste (Name, Telefon, E-Mail usw.) und einen zweiten Tisch, an dem die Anzahl der angemeldeten Gäste erfasst wird. Wir haben also zwei Operationen für eine "Transaktion". Angenommen, nach dem Hinzufügen der Gastinformationen zur GUESTS-Tabelle tritt ein Verbindungsverlust oder ein Fehler mit derselben Auswirkung auf. Die GUESTS-Tabelle wurde aktualisiert (eingefügt), aber die Verbindung wurde unterbrochen, bevor die "verfügbaren Plätze" aktualisiert werden konnten.

Jetzt haben wir einen Gast zum Gästetisch hinzugefügt, aber die Anzahl der verfügbaren Plätze ist jetzt falsch (zum Beispiel ist der Wert 85, wenn er tatsächlich 84 ist).

Natürlich gibt es viele Möglichkeiten, dies zu handhaben, z. B. die Verfolgung verfügbarer Plätze mit "100 minus Anzahl der Zeilen in der Gästetabelle" oder einen Code, der überprüft, ob die Informationen konsistent sind usw. Aber mit einer transaktionsbasierten Datenbank Bei einer Engine wie InnoDB werden entweder ALLE Vorgänge festgeschrieben oder KEINE von ihnen. Dies kann in vielen Fällen hilfreich sein, aber wie gesagt, es ist nicht der EINZIGE Weg, um sicher zu sein, nein (ein guter Weg, der jedoch von der Datenbank und nicht vom Programmierer / Drehbuchautor gehandhabt wird).

Das ist alles, was "transaktionsbasiert" in diesem Zusammenhang im Wesentlichen bedeutet, es sei denn, ich vermisse etwas - dass entweder die gesamte Transaktion so erfolgreich ist, wie sie sollte, oder dass nichts geändert wird, da nur teilweise Änderungen das SEVERE-Chaos geringfügig beeinträchtigen können Datenbank, vielleicht sogar beschädigt ...

Aber ich werde es noch einmal sagen, es ist nicht der einzige Weg, um ein Durcheinander zu vermeiden. Aber es ist eine der Methoden, die die Engine selbst handhabt, sodass Sie sich nur noch darum kümmern müssen, ob die Transaktion erfolgreich war oder nicht, und was mache ich, wenn nicht (z. B. erneut versuchen), anstatt manuell Schreiben von Code, um ihn "manuell" von außerhalb der Datenbank zu überprüfen, und viel mehr Arbeit für solche Ereignisse.

Zum Schluss noch ein Hinweis zum Sperren von Tabellen und zum Sperren von Zeilen:

HAFTUNGSAUSSCHLUSS: Ich kann mich in allem, was in Bezug auf MySQL folgt, irren, und die hypothetischen / Beispielsituationen sind Dinge, die untersucht werden müssen, aber ich kann mich irren, was genau möglich ist, mit MySQL Korruption zu verursachen. Die Beispiele sind jedoch in der allgemeinen Programmierung sehr real, selbst wenn MySQL über mehr Mechanismen verfügt, um solche Dinge zu vermeiden ...

Wie dem auch sei, ich bin ziemlich zuversichtlich , mit denen bei der Vereinbarung , die argumentiert haben , dass , wie viele Verbindungen gleichzeitig erlaubt ist nicht eine gesperrte Tabelle umgehen. In der Tat sind mehrere Verbindungen der gesamte Punkt, um eine Tabelle zu sperren !! Damit andere Prozesse / Benutzer / Apps die Datenbank nicht durch gleichzeitige Änderungen beschädigen können.

Wie würden zwei oder mehr Verbindungen, die in derselben Zeile arbeiten, einen WIRKLICH SCHLECHTEN TAG für Sie bedeuten? Angenommen, es gibt zwei Prozesse, die beide denselben Wert in derselben Zeile aktualisieren möchten / müssen, beispielsweise weil die Zeile eine Aufzeichnung einer Bustour ist und jeder der beiden Prozesse gleichzeitig die "Fahrer" oder "verfügbaren_Sitze" aktualisieren möchte. Feld als "der aktuelle Wert plus 1."

Lassen Sie uns dies hypothetisch Schritt für Schritt tun:

  1. Prozess eins liest den aktuellen Wert, sagen wir, er ist leer, also '0' bis jetzt.
  2. Prozess zwei liest auch den aktuellen Wert, der immer noch 0 ist.
  3. Prozess, den man schreibt (aktuell + 1), ist 1.
  4. Prozess zwei sollte 2 schreiben, aber da er den aktuellen Wert liest, bevor Prozess eins den neuen Wert schreibt, schreibt auch er 1 in die Tabelle.

Ich bin mir nicht sicher, ob sich zwei Verbindungen so vermischen könnten, beide lesen, bevor der erste schreibt ... Aber wenn nicht, dann würde ich immer noch ein Problem sehen mit:

  1. Prozess eins liest den aktuellen Wert, der 0 ist.
  2. Prozess, den man schreibt (aktuell + 1), was 1 ist.
  3. Prozess zwei liest jetzt den aktuellen Wert. Während des ersten DID-Schreibvorgangs (Aktualisieren) wurden die Daten nicht festgeschrieben, sodass nur derselbe Prozess den neuen Wert lesen kann, den er aktualisiert hat, während alle anderen den älteren Wert sehen, bis ein Festschreiben erfolgt.

Zumindest bei Oracle-Datenbanken gibt es auch Isolationsstufen, die ich nicht mit Paraphrasen verschwenden werde. Hier ist ein guter Artikel zu diesem Thema, und jede Isolationsstufe hat ihre Vor- und Nachteile, die damit einhergehen, wie wichtig transaktionsbasierte Engines in einer Datenbank sein können ...

Schließlich gibt es in MyISAM möglicherweise andere Sicherheitsvorkehrungen als Fremdschlüssel und transaktionsbasierte Interaktion. Zum einen gibt es die Tatsache, dass eine ganze Tabelle gesperrt ist, was es weniger wahrscheinlich macht, dass Transaktionen / FKs benötigt werden .

Und leider, wenn Sie sich dieser Parallelitätsprobleme bewusst sind, können Sie auf Nummer sicher gehen und einfach Ihre Anwendungen schreiben und Ihre Systeme so einrichten, dass solche Fehler nicht möglich sind (Ihr Code ist dann verantwortlich und nicht die Datenbank selbst). Meiner Meinung nach würde ich jedoch sagen, dass es immer am besten ist, so viele Sicherheitsvorkehrungen wie möglich zu treffen, defensiv zu programmieren und sich immer bewusst zu sein, dass menschliches Versagen unmöglich vollständig zu vermeiden ist. Es passiert jedem, und jeder, der sagt, dass er dagegen immun ist, muss lügen oder hat nicht mehr getan, als eine "Hello World" -Anwendung / ein Skript zu schreiben. ;-);

Ich hoffe, dass EINIGES davon für jemanden hilfreich ist, und noch mehr, ich hoffe, dass ich nicht gerade jetzt ein Schuldiger von Annahmen war und ein Mensch im Irrtum war !! Ich entschuldige mich, wenn ja, aber die Beispiele sind gut zu überlegen, das Risiko zu untersuchen und so weiter, auch wenn sie in diesem speziellen Kontext nicht potenziell sind.

Fühlen Sie sich frei, mich zu korrigieren, diese "Antwort" zu bearbeiten und sogar abzustimmen. Versuchen Sie einfach, sich zu verbessern, anstatt eine schlechte Annahme von mir mit einer anderen zu korrigieren. ;-);

Dies ist meine erste Antwort, bitte verzeihen Sie die Länge aufgrund aller Haftungsausschlüsse usw. Ich möchte einfach nicht arrogant klingen, wenn ich nicht absolut sicher bin!

Arembjorn
quelle
5

Nach meiner Erfahrung war MyISAM die bessere Wahl, solange Sie keine DELETEs, UPDATEs, viele einzelne INSERT-Transaktionen, Transaktionen und Volltextindizierungen ausführen. Übrigens, CHECK TABLE ist schrecklich. Da die Tabelle in Bezug auf die Anzahl der Zeilen älter wird, wissen Sie nicht, wann sie enden wird.

Yogman
quelle
2
Die Volltextindizierung ist nur mit MyISAM möglich, nicht mit InnoDB.
Pixel Elephant
2
@ PixelElephant, das beginnt sich in MySQL 5.6 zu ändern. InnoDB hat einen Volltext-Indextyp, ist aber meiner Meinung nach noch nicht produktionsbereit.
Bill Karwin
1
"Volltextindizierung ist nur mit MyISAM möglich, nicht mit InnoDB": nicht mehr wahr, da MySQL> = 5.6. Siehe dev.mysql.com/doc/refman/5.6/en/fulltext-search.html .
Hibou57
5

Ich habe herausgefunden, dass Myisam, obwohl es Sperrenkonflikte gibt, in den meisten Szenarien aufgrund des verwendeten Schlosserfassungsschemas immer noch schneller als InnoDb ist. Ich habe Innodb mehrmals ausprobiert und greife aus dem einen oder anderen Grund immer auf MyIsam zurück. Auch InnoDB kann bei großen Schreiblasten sehr CPU-intensiv sein.

Ricardo
quelle
4

Jede Anwendung verfügt über ein eigenes Leistungsprofil für die Verwendung einer Datenbank, das sich wahrscheinlich im Laufe der Zeit ändert.

Das Beste, was Sie tun können, ist, Ihre Optionen zu testen. Das Wechseln zwischen MyISAM und InnoDB ist trivial. Laden Sie also einige Testdaten und feuern Sie jmeter gegen Ihre Site und sehen Sie, was passiert.

Gary Richardson
quelle
4

Ich habe versucht, zufällige Daten in MyISAM- und InnoDB-Tabellen einzufügen. Das Ergebnis war ziemlich schockierend. MyISAM benötigte ein paar Sekunden weniger zum Einfügen von 1 Million Zeilen als InnoDB für nur 10 Tausend!

user965748
quelle
2
Sie erhalten die gleiche Leistung, wenn Sie die Transaktion verwenden und die automatische Festschreibung für die InnoDB-Engine deaktivieren.
Stanleyxu2005
IDK ist die gleiche Leistung, aber das ist es, was ich in komplexeren Anwendungen mache und es beschleunigt es.
user965748
1
Sie haben die genauen Details Ihres Experiments nicht angegeben - welche Konfigurationseinstellungen? Was war vorher in den Tabellen? Welche Art von Daten? und vielleicht am wichtigsten - gab es sequentielle Beilagen? Parallel? Was war ihr Timing? Wie viele CPU-Kerne? Themen? etc.
Einpoklum
3

myisam ist ein NOGO für diese Art von Workload (Schreibvorgänge mit hoher Parallelität). Ich habe nicht so viel Erfahrung mit innodb (habe es dreimal getestet und in jedem Fall festgestellt, dass die Leistung schlecht war, aber es ist eine Weile her seit dem letzten Test), wenn Sie Ich bin nicht gezwungen, MySQL auszuführen. Versuchen Sie es mit Postgres, da es gleichzeitige Schreibvorgänge VIEL besser handhabt

pfote
quelle
3

Kurz gesagt, InnoDB ist gut, wenn Sie an etwas arbeiten, das eine zuverlässige Datenbank benötigt, die viele INSERT- und UPDATE-Anweisungen verarbeiten kann.

und MyISAM ist gut, wenn Sie eine Datenbank benötigen, die meistens viele Leseanweisungen (SELECT) anstelle von Schreibanweisungen (INSERT und UPDATES) benötigt, wenn man den Nachteil der Tabellensperre berücksichtigt.

Vielleicht möchten Sie auschecken.
Vor- und Nachteile von InnoDB
Vor- und Nachteile von MyISAM

Light93
quelle
2

Ich weiß, dass dies nicht beliebt sein wird, aber hier ist:

myISAM bietet keine Unterstützung für Datenbankdaten wie Transaktionen und referenzielle Integrität, was häufig zu fehlerhaften / fehlerhaften Anwendungen führt. Sie können nicht die richtigen Grundlagen für das Datenbankdesign lernen, wenn diese nicht einmal von Ihrer Datenbank-Engine unterstützt werden.

Wenn Sie in der Datenbankwelt keine referenzielle Integrität oder Transaktionen verwenden, ist dies so, als würden Sie in der Software-Welt keine objektorientierte Programmierung verwenden.

InnoDB existiert jetzt, benutze das stattdessen! Sogar MySQL-Entwickler haben endlich zugestanden, dies in neueren Versionen auf die Standard-Engine zu ändern, obwohl myISAM die ursprüngliche Engine war, die in allen Legacy-Systemen die Standardeinstellung war.

Nein, es spielt keine Rolle, ob Sie lesen oder schreiben oder welche Leistungsaspekte Sie haben. Die Verwendung von myISAM kann zu einer Reihe von Problemen führen, z. B. dem, auf das ich gerade gestoßen bin: Ich habe eine Datenbanksynchronisierung durchgeführt und gleichzeitig eine andere Person Zugriff auf eine Anwendung, die auf eine auf myISAM festgelegte Tabelle zugegriffen hat. Aufgrund der fehlenden Transaktionsunterstützung und der allgemein schlechten Zuverlässigkeit dieser Engine stürzte die gesamte Datenbank ab und ich musste mysql manuell neu starten!

In den letzten 15 Jahren meiner Entwicklung habe ich viele Datenbanken und Engines verwendet. myISAM stürzte in dieser Zeit ungefähr ein Dutzend Mal auf mich ab, andere Datenbanken nur einmal! Und das war eine Microsoft SQL-Datenbank, in der einige Entwickler fehlerhaften CLR-Code (Common Language Runtime - im Grunde C # -Code, der in der Datenbank ausgeführt wird) geschrieben haben. Es war übrigens nicht genau der Fehler des Datenbankmoduls.

Ich stimme den anderen Antworten hier zu, die besagen, dass hochwertige Hochverfügbarkeits- und Hochleistungsanwendungen myISAM nicht verwenden sollten, da es nicht funktioniert, nicht robust oder stabil genug ist, um eine frustrationsfreie Erfahrung zu erzielen. Weitere Einzelheiten finden Sie in der Antwort von Bill Karwin.

PS Ich muss es lieben, wenn myISAM-Fanboys abstimmen, aber ich kann dir nicht sagen, welcher Teil dieser Antwort falsch ist.

pilavdzice
quelle
5
Ich habe nicht abgelehnt, aber wenn ich es getan hätte, wäre es für die Beratung, niemals zu verwenden. Das Wort sollte niemals im Vokabular eines Entwicklers niedergeschlagen werden ... Einschränkung: "Sag niemals nie".
Hubson Bropa
1

Für dieses Verhältnis von Lesen / Schreiben würde InnoDB vermutlich eine bessere Leistung erbringen. Da Sie mit schmutzigen Lesevorgängen einverstanden sind, können Sie (wenn Sie es sich leisten) auf einen Slave replizieren und alle Ihre Lesevorgänge an den Slave gehen lassen. Ziehen Sie auch in Betracht, nicht nur einen Datensatz, sondern jeweils in großen Mengen einzufügen.

Neal Aise
quelle
1

Fast jedes Mal, wenn ich ein neues Projekt starte, google ich dieselbe Frage, um zu sehen, ob ich neue Antworten finde.

Es läuft schließlich darauf hinaus - ich nehme die neueste Version von MySQL und führe Tests durch.

Ich habe Tabellen, in denen ich Schlüssel- / Wertsuchen durchführen möchte ... und das ist alles. Ich muss den Wert (0-512 Bytes) für einen Hash-Schlüssel erhalten. Es gibt nicht viele Transaktionen in dieser Datenbank. Die Tabelle wird gelegentlich (in ihrer Gesamtheit) aktualisiert, jedoch mit 0 Transaktionen.

Wir sprechen hier also nicht von einem komplexen System, sondern von einer einfachen Suche. Und wie wir (abgesehen davon, dass der Tabellen-RAM resident ist) die Leistung optimieren können.

Ich mache auch Tests mit anderen Datenbanken (dh NoSQL), um zu sehen, ob es irgendwo einen Vorteil gibt. Der größte Vorteil, den ich gefunden habe, liegt in der Schlüsselzuordnung, aber was die Suche angeht, übertrifft MyISAM derzeit alle.

Ich würde zwar keine Finanztransaktionen mit MyISAM-Tabellen durchführen, aber für einfache Suchvorgänge sollten Sie es testen. In der Regel 2x bis 5x die Abfragen / Sek.

Testen Sie es, ich begrüße die Debatte.

Cyberwip
quelle
1

Wenn es sich um 70% Einfügungen und 30% Lesevorgänge handelt, ähnelt dies eher der InnoDB-Seite.

kta
quelle
0

Fazit: Wenn Sie offline mit ausgewählten Datenblöcken arbeiten, bietet Ihnen MyISAM wahrscheinlich bessere (viel bessere) Geschwindigkeiten.

Es gibt Situationen, in denen MyISAM unendlich effizienter als InnoDB ist: Wenn große Datenabbilder offline bearbeitet werden (aufgrund der Tabellensperre).

Beispiel: Ich habe eine CSV-Datei (15 Millionen Datensätze) von NOAA konvertiert, die VARCHAR-Felder als Schlüssel verwendet. InnoDB dauerte ewig, selbst wenn große Speicherblöcke verfügbar waren.

Dies ist ein Beispiel für die CSV (erstes und drittes Feld sind Schlüssel).

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,

Da ich ein Batch-Offline-Update der beobachteten Wetterphänomene ausführen muss, verwende ich die MyISAM-Tabelle zum Empfangen von Daten und führe JOINS auf den Schlüsseln aus, damit ich die eingehende Datei bereinigen und VARCHAR-Felder durch INT-Schlüssel ersetzen kann (die sich darauf beziehen externe Tabellen, in denen die ursprünglichen VARCHAR-Werte gespeichert sind).

Tony Gil
quelle