Quali sono i motivi ** NON ** per utilizzare il motore di archiviazione MEMORY in MySQL?


28

Recentemente ho scoperto che MySQL ha un motore di "memoria" di cui non ero a conoscenza (la maggior parte del mio lavoro di database è per progetti di hobbistica, quindi imparo ciò di cui ho bisogno mentre vado). Sembra che questa opzione dovrebbe darmi prestazioni drasticamente migliorate, quindi mi chiedo se ci siano degli svantaggi. I due che conosco sono:

  1. Devo avere abbastanza RAM per contenere le tabelle in questione.
  2. Le tabelle vanno perse se la macchina si spegne.

Credo che il numero 1 non dovrebbe essere un problema dal momento che sto usando AWS EC2 e, se necessario, posso passare a un tipo di istanza con più memoria. Credo di poter mitigare il n. 2 scaricando di nuovo su disco secondo necessità.

Quali altri problemi ci sono? Il motore di memoria può mai offrire prestazioni peggiori di MyISAM o InnoDB? Penso di aver letto qualcosa che gli indici sono diversi con questo motore; è qualcosa di cui devo preoccuparmi?

Risposte:


27

Guardando l'elenco di disponibilità delle funzionalità su http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html, due possibili problemi saltano fuori:

  1. Nessuna transazione o supporto FK, il che significa che dovrai gestire l'integrità transazionale e l'integrità referenziale nel tuo codice (che potrebbe finire per essere molto meno efficiente che lasciare che il DB faccia questo per te, anche se dipende molto dalla tua app modelli di comportamento previsti).
  2. Solo blocco a livello di tabella: questo potrebbe rappresentare un ostacolo significativo alla scalabilità se l'app richiede più writer simultanei sullo stesso set di tabelle o nei casi in cui le operazioni di lettura utilizzano i blocchi per garantire la lettura di dati coerenti, in questi casi una tabella basata su disco che supporta un blocco molto più preciso la granularità funzionerà molto meglio se una quantità sufficiente del suo contenuto è attualmente memorizzata nella cache nella RAM.

Oltre a ciò, supponendo che tu abbia abbastanza RAM, una tabella basata sulla memoria dovrebbe essere più veloce di una basata sul disco. Ovviamente è necessario considerare le istantanee su disco per risolvere il problema di ciò che accade quando viene ripristinata l'istanza del server, il che probabilmente annullerà completamente il vantaggio in termini di prestazioni nel caso in cui i dati debbano essere acquisiti spesso (se riesci a vivere perdendo un giorno di i dati in tal caso si potrebbe semplicemente fare un backup una volta al giorno, ma nella maggior parte dei casi ciò non sarebbe accettabile).

Un'alternativa potrebbe essere quella di:

  1. Utilizza le tabelle basate su disco, ma assicurati di disporre di una RAM più che sufficiente per conservarle tutte nella RAM in qualsiasi momento (e che "sufficiente RAM" potrebbe essere più di quanto pensi in quanto è necessario tenere conto di qualsiasi altro processo sul computer, sistema operativo Buffer / cache IO e così via)
  2. Scansiona l'intero contenuto (tutti i dati e le pagine dell'indice) della tabella su ogni avvio per precaricare il contenuto in memoria con SELECT * FROM <table> ORDER BY <pkey fields>per ogni tabella seguita da SELECT <indexed fields> FROM <table> ORDER BY <index fields>per ogni indice

In questo modo tutti i tuoi dati sono nella RAM, devi solo preoccuparti delle prestazioni I / O per le operazioni di scrittura. Se il set di lavoro comune della tua app è molto più piccolo dell'intero DB (cosa che di solito accade - nella maggior parte delle applicazioni la maggior parte degli utenti guarderà i dati più recenti solo se in quel momento) potresti essere meglio di essere più selettivo su quanto si esegue la scansione per precaricare in memoria, consentendo il resto da caricare su disco su richiesta.


Perché avresti bisogno dell'integrità transazionale per un database in memoria? Se la corrente si spegne, stai perdendo tutto comunque.
osa,

@osa: supponendo che consenta l'accesso simultaneo piuttosto che serializzare tutto, vorrai una qualche forma di gestione dell'integrità per questo.
David Spillett,

14

Esistono molti casi per non utilizzare il motore di archiviazione della memoria e quando InnoDB sarà più veloce. Devi solo pensare alla concorrenza e non ai banali test a thread singolo.

Se si dispone di un pool buffer abbastanza grande, InnoDB diventerà interamente residente in memoria anche per le operazioni di lettura. I database hanno cache . Si riscaldano!

Inoltre, non sottovalutare il valore del blocco a livello di riga e MVCC (i lettori non bloccano i writer). Potrebbe essere "più lento" quando le scritture devono persistere su disco. Ma almeno non ti blocchi durante quell'operazione di scrittura come se fossi su una tabella di memoria (nessun MVCC; blocco a livello di tabella).


3

Per il record. Ho testato le tabelle Mysql in memoria per memorizzare alcune informazioni. E ho testato l'APC (APCu) di PHP per memorizzare le stesse informazioni.

Per 58000 registri. (varchar + intero + data).

  1. Informazioni originali 24mb in formato testo (formato csv).
  2. L'APC di PHP utilizza 44,7 MB di RAM.
  3. Mysql's Table utilizza 575 MB di RAM.

La tabella ha un solo indice quindi non penso che sia il fattore principale.

Conclusione:

La tabella di memoria non è un'opzione per le tabelle "grandi" perché utilizza troppa memoria.


2
Questa è una risposta semplificata. Il motore di archiviazione MEMORY può essere ottimizzato utilizzando tipi di dati più piccoli, definendo esplicitamente BTREE come tipo di indice e limitando la quantità di dati caricati nella RAM. È ancora un'opzione praticabile per set più piccoli. Esistono anche altri fattori come l'I / O del disco aggressivo. Vedi i miei post dba.stackexchange.com/questions/6156/… e dba.stackexchange.com/questions/2868/… )
RolandoMySQLDBA

In effetti, ho controllato cambiando l'indice (e persino cancellandolo completamente) e le dimensioni non sono cambiate molto (inclusa una ricostruzione del tavolo da zero). IMHO Mysql sta facendo qualcosa sotto il cofano, potrebbe essere una sorta di ottimizzazione o allocare la dimensione più grande per colonna (come in un varchar).
Magallanes,

6
Il motivo è quasi certamente dovuto al tuo VARCHAR: "MEMORY tables use a fixed-length row-storage format. Variable-length types such as VARCHAR are stored using a fixed length." dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html In effetti sembrerebbe che VARCHAR diventi CHAR con il motore MEMORY.
Matteo 1471,

2

L'altro svantaggio delle tabelle basate su MEMORY è che non possono essere indirizzate più volte nella stessa query. Almeno quel comportamento è stato trovato fino alla v5.4. Come con i CTE (dalla v8.x) non è necessario utilizzare tabelle intermedie basate su mem per procedure complesse.


1

Secondo i manuali MySQL e MariaDB, BLOB e CLOB (vari tipi di TEXT) non sono supportati dalla memoria MEMORY. Per i nostri scopi, ciò ha reso il motore di archiviazione MEMORY quasi inutile.

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

Le tabelle MEMORY non possono contenere colonne BLOB o TEXT.

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

Tipi di lunghezza variabile come VARCHAR possono essere utilizzati nelle tabelle MEMORY. Le colonne BLOB o TEXT non sono supportate per le tabelle MEMORY.

Quando ho provato a convertire solo una parte del database in memoria MEMORY, ho scoperto che le chiavi esterne del motore di archiviazione non sono supportate. Quindi, tutte le tabelle, che dovrebbero avere riferimenti a chiave esterna alle tabelle, contenenti BLOB / CLOB dovrebbero anche essere in tipi di memoria non di memoria (almeno, ciò influisce sulle tabelle figlio di InnoDB).


1

Le tabelle MEMORY non sono intese per l'archiviazione persistente, in particolare di grandi sottoinsiemi di dati o di qualsiasi cosa in cui la conservazione è fondamentale. Il loro scopo migliore dalla mia esperienza è quello di ospitare registrazioni transitorie durante la creazione e il popolamento di tabelle temporanee durante procedure complesse, che si comporta in modo significativamente più veloce rispetto alla maggior parte degli altri tipi di tabella a questo scopo, a condizione che la soglia del buffer chiave per il motore sia impostata abbastanza in alto da non incorrere in una scrittura su disco. Questo può operare a un ordine di grandezza più veloce di MyISAM o InnoDB per questo scopo in quanto non vi è I / O del disco, e nel caso di una tabella che è incapsulata in una procedura specifica, l'indicizzazione e le relazioni non hanno tanto significato quanto loro dove sarebbe prevista la persistenza.


1

Oltre alle risposte precedenti. direttamente dal manuale di MySQL 5.7:

"Le prestazioni della MEMORIA sono limitate dalla contesa derivante dall'esecuzione a thread singolo e dal sovraccarico del blocco della tabella durante l'elaborazione degli aggiornamenti. Ciò limita la scalabilità quando aumenta il carico, in particolare per i mix di istruzioni che includono le scritture."

... e questa è una vera limitazione. Ad esempio: quando si hanno più sessioni che provano a creare tabelle temporanee MEMORY veloci e veloci, il single threading può causare seri colli di bottiglia nelle prestazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.