Modifica il limite per "Mysql Row size too large"


104

Come posso modificare il limite

La dimensione della riga è troppo grande (> 8126). Cambiare alcune colonne in TEXT o BLOB o usare ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSEDpuò aiutare. Nel formato riga corrente, il BLOBprefisso di 768 byte viene memorizzato in linea.

Tavolo:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 

1
Qual è la Novisualizzazione?
hjpotter92

Impossibile aggiornare l'errore "La dimensione della riga è troppo grande (> 8126). La modifica di alcune colonne in TEXT o BLOB o l'utilizzo di ROW_FORMAT = DYNAMIC o ROW_FORMAT = COMPRESSED potrebbe essere d'aiuto. Nel formato di riga corrente, il prefisso BLOB di 768 byte è memorizzato in linea."
Lasha Kurt

Puoi aggiungere qualche altro dettaglio al tuo post, almeno come commento?
Eineki

1
se questi dati si trovano in un'altra tabella, considera l'utilizzo di una chiave esterna, ciò ridurrà drasticamente la dimensione della riga e normalizzerà lo schema del database.
didierc

1
@AL: Oops, hai ragione - vota da vicino l'altro
pathikrit

Risposte:


121

La domanda è stata posta anche su serverfault .

Potresti dare un'occhiata a questo articolo che spiega molto sulle dimensioni delle righe di MySQL. È importante notare che anche se utilizzi i campi TEXT o BLOB, la dimensione della tua riga potrebbe comunque essere superiore a 8K (limite per InnoDB) perché memorizza i primi 768 byte per ogni campo in linea nella pagina.

Il modo più semplice per risolvere questo problema è utilizzare il formato di file Barracuda con InnoDB. Questo fondamentalmente elimina del tutto il problema memorizzando solo il puntatore a 20 byte ai dati di testo invece di memorizzare i primi 768 byte.


Il metodo che ha funzionato per l'OP era:

  1. Aggiungi quanto segue al my.cnffile nella [mysqld]sezione.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
  2. ALTERil tavolo da usare ROW_FORMAT=COMPRESSED.

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;

È possibile che quanto sopra ancora non risolva i tuoi problemi. È un bug noto (e verificato) con il motore InnoDB e una soluzione temporanea per ora è il fallback al motore MyISAM come memoria temporanea. Quindi, nel tuo my.cnffile:

internal_tmp_disk_storage_engine=MyISAM

12
+1 -> La parte innodb_file_per_table è cruciale e va di pari passo con la modifica del formato in Barracuda. Senza di esso, MySQL continuerà silenziosamente a utilizzare Antelope.
Nick

1
@ Eduardo, consiglierei di eseguire prima il backup dei dati. Ma sì, puoi farlo anche in produzione!
hjpotter92

3
Utilizzare innodb_file_per_table=1per attivare questa opzione.
Stijn Geukens

2
Non è garantito che questo risolva il problema. Vedi questo post per uno script di esempio che aggiunge queste impostazioni ma è ancora in grado di riprodurre l'errore.
Cerin

1
@ user1183352 Aggiornata la mia risposta sopra. Grazie per avermi ricordato di nuovo di approfondire questo argomento. :)
hjpotter92

61

Mi sono imbattuto in questo problema di recente e l'ho risolto in un modo diverso. Se stai utilizzando MySQL versione 5.6.20, è presente un bug noto nel sistema. Vedi la documentazione di MySQL

Importante A causa del bug n. 69477, le scritture del registro di ripetizione per campi BLOB di grandi dimensioni archiviati esternamente potrebbero sovrascrivere il punto di controllo più recente. Per risolvere questo bug, una patch introdotta in MySQL 5.6.20 limita la dimensione delle scritture BLOB del registro di ripristino al 10% della dimensione del file di registro di ripristino. Come risultato di questo limite, innodb_log_file_size dovrebbe essere impostato su un valore maggiore di 10 volte la dimensione dei dati BLOB più grande trovata nelle righe delle tabelle più la lunghezza di altri campi di lunghezza variabile (campi di tipo VARCHAR, VARBINARY e TEXT).

Nella mia situazione la tabella blob incriminata era di circa 16 MB. Quindi, il modo in cui l'ho risolto è stato aggiungendo una riga a my.cnf che mi assicurava di avere almeno 10 volte quella quantità e poi alcuni:

innodb_log_file_size = 256M


Azzeccato. Il mio errore "Row Size too large" su un longblobcampo è scomparso non appena ho aumentato il innodb_log_file_sizeparametro. Inoltre era in esecuzione 5.6.20.
adamup

Grazie. Stavo eseguendo homebrew 5.6.21, la modifica del parametro ha risolto il problema.
nanoman

Sia questa che la risposta di @ hjpotter92 erano necessarie per correggere questo errore per me.
Cerin

Grazie. Era in esecuzione 5.6.21 e questa soluzione ha aiutato.
petiar

Anche questo non ha risolto il mio problema. Sto pensando di sostituire molti dei miei campi VARCHAR con TEXT, come ho visto su thread simili.
PDoria

28

Imposta i seguenti sul tuo file my.cnf e riavvia il server mysql.

innodb_strict_mode=0

2
innodb_strict_mode=0-> senza spazi. In caso contrario, il riavvio di mariaDB 10.2 restituisce un errore :-P
Pathros

Non ho provato con mariadb, per MySQL non ha bisogno di rimuovere spazi.
Karl

1
Secondo la documentazione, disabilitare la modalità rigorosa impedisce solo la visualizzazione di errori e avvisi, quindi non sembra risolvere il problema! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira

2
Questo sembra funzionare e mi permette di creare le tabelle senza problemi e memorizzare i dati
Chris Muench

@ João, fa di più .. dev.mysql.com/doc/refman/8.0/en/…
Karl

24

Se puoi cambiare ENGINE e utilizzare MyISAM invece di InnoDB, ciò dovrebbe aiutare:

ENGINE=MyISAM

Ci sono due avvertenze con MyISAM (probabilmente di più):

  1. Non puoi utilizzare le transazioni.
  2. Non puoi usare vincoli di chiave esterna.

5
Va bene se non ti dispiace andare senza transazioni e vincoli di chiave esterna. Ma tieni presente che questi li perdi quando passi a MyISAM.
wobbily_col

Questo consiglio è folle - almeno la frase farà tutti gli avvertimenti! Le transazioni e i vincoli chiave precedenti sono l'ultimo dei problemi con questo formato!
Hassan Syed

Spiacenti, ho downvotato questa risposta. Aggiorna per menzionare tutti gli avvertimenti coinvolti. Chiunque segua questo consiglio passa a un formato che non utilizzerei mai su nessun sistema di produzione.
Remco Wendt

2
E MyISAM sta andando via.
Rick James

2
ha funzionato per me. Nel mio caso avevo oltre 300 campi di circa 10 di lunghezza ciascuno. Non ho alcuna relazione in questa tabella, quindi il passaggio a MyISAM è stata la soluzione.
Robert Saylor

12

Vorrei condividere una risposta fantastica, potrebbe essere utile. Crediti Bill Karwin vede qui /dba/6598/innodb-create-table-error-row-size-too-large

Variano in base al formato di file InnoDB. Attualmente ci sono 2 formati chiamati Antelope e Barracuda.

Il file del tablespace centrale (ibdata1) è sempre in formato Antelope. Se usi file-per-table, puoi fare in modo che i singoli file utilizzino il formato Barracuda impostando innodb_file_format = Barracuda in my.cnf.

Punti fondamentali:

  1. Una pagina da 16 KB di dati InnoDB deve contenere almeno due righe di dati. Inoltre, ogni pagina ha un'intestazione e un piè di pagina contenenti i checksum della pagina e il numero di sequenza del registro e così via. È qui che ottieni il limite di poco meno di 8 KB per riga.

  2. I tipi di dati a dimensione fissa come INTEGER, DATE, FLOAT, CHAR sono archiviati in questa pagina di dati primari e vengono conteggiati per il limite di dimensione della riga.

  3. I tipi di dati di dimensioni variabili come VARCHAR, TEXT, BLOB sono archiviati nelle pagine di overflow, quindi non vengono conteggiati completamente per il limite di dimensione della riga. In Antelope, fino a 768 byte di tali colonne vengono memorizzati nella pagina dei dati primari oltre a essere memorizzati nella pagina di overflow. Barracuda supporta un formato di riga dinamico, quindi può memorizzare solo un puntatore a 20 byte sulla pagina dei dati primari.

  4. Anche i tipi di dati a dimensione variabile sono preceduti da 1 o più byte per codificare la lunghezza. E il formato di riga InnoDB ha anche una serie di offset di campo. Quindi c'è una struttura interna più o meno documentata nel loro wiki.

Barracuda supporta anche ROW_FORMAT = COMPRESSED per ottenere un'ulteriore efficienza di archiviazione per i dati in eccesso.

Devo anche commentare che non ho mai visto una tabella ben progettata superare il limite di dimensione delle righe. È un forte "odore di codice" che stai violando la condizione dei gruppi ripetuti della prima forma normale.


7

Ho avuto lo stesso problema, questo lo ha risolto per me:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

Dalla documentazione MYSQL :

Il formato riga DYNAMIC mantiene l'efficienza di memorizzare l'intera riga nel nodo indice se si adatta (come fanno i formati COMPACT e REDUNDANT), ma questo nuovo formato evita il problema di riempire i nodi B-tree con un gran numero di byte di dati di lunghe colonne. Il formato DYNAMIC si basa sull'idea che se una parte di un valore di dati lunghi viene archiviata fuori pagina, di solito è più efficiente memorizzare tutto il valore fuori pagina. Con il formato DYNAMIC, è probabile che le colonne più corte rimangano nel nodo B-tree, riducendo al minimo il numero di pagine di overflow necessarie per una determinata riga.


... ma devi avere un formato di file diverso, quindi sei già su Barracuda? Perché ricevo un errore provando quel comando, dicendoWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted

Quando ho lasciato che HeidiSQL eseguisse lo stesso comando tramite la sua GUI integrata, in qualche modo è riuscito, ma non ha aiutato affatto, ottengo lo stesso errore,Row size too large (>8126)
Ted

Prova a impostare innodb_file_format = Barracuda in my.ini e prova ALTER TABLE my_tableROW_FORMAT = DYNAMIC; di nuovo
multimediaxp

Sì, penso che sia quello che ho fatto alla fine, e penso che questo abbia risolto tutto. Ma ho anche cambiato molte colonne in TEXT allo stesso tempo in preda alla disperazione =) Grazie, però, in realtà penso che fosse così.
Ted

Bene !, se pensi che questa sia una buona risposta, dai un voto positivo e accetta come risposta valida, grazie!
multimediaxp

5

Dopo aver passato ore ho trovato la soluzione: basta eseguire il seguente SQL nel tuo amministratore MySQL per convertire la tabella in MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;

Non aiuta molto se il problema si verifica in un'istruzione create table.
Mark Fraser

create tableha la stessa opzione:CREATE TABLE ... ENGINE=MyISAM ...
xebeche

3

Mi sono imbattuto in questo problema quando stavo cercando di ripristinare un database mysql di backup da un server diverso. Ciò che ha risolto questo problema per me è stato l'aggiunta di determinate impostazioni a my.conf (come nelle domande sopra) e inoltre la modifica del file di backup sql:

Passaggio 1: aggiungi o modifica le seguenti righe in my.conf:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Passaggio 2 aggiungere ROW_FORMAT = DYNAMIC all'istruzione di creazione della tabella nel file di backup sql per la tabella che causa questo errore:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

l'importante modifica sopra è ROW_FORMAT = DYNAMIC;(che non era incluso nel file di backup sql originale)

fonte che mi ha aiutato a risolvere questo problema: MariaDB e InnoDB MySQL Row dimensioni troppo grandi


1
Le righe descritte al passaggio 1 non dovrebbero avere spazio. La linea innodb_page_size=32Knon ha funzionato, poiché nel mio caso ha causato un errore nel riavviare MariaDB 10.2. Invece, ho aggiunto la innodb_strict_mode=0riga, come descritto qui
Pathros

1
grazie per il feedback Pathros, ho aggiornato la mia risposta e rimosso gli spazi dal passaggio 1.
matyas

Nota per MySQL <= 5.7.5: 32K non è un'opzione valida per innodb_page_size. Vedi: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar

Inoltre, è necessario ricreare l'intero server mysql per scracth, poiché il cambiamento innodb_page_sizerichiede la ibdata*ricreazione, che è un'operazione distruttiva. Guarda il tuo syslog per ulteriori informazioni
Matija Nalis

2

Le altre risposte affrontano la domanda posta. Affronterò la causa sottostante: una cattiva progettazione dello schema.

Non distribuire un array su colonne. Qui hai 3 * 10 colonne che dovrebbero essere trasformate in 10 righe di 3 colonne in una nuova tabella (piùid , ecc.)

Il tuo Maintavolo avrebbe solo

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

Il tuo tavolo extra ( Top) avrebbe

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

Ci sarebbero 10 (o meno? O più?) Righe Topper ciascuna id.

Ciò elimina il problema originale e ripulisce lo schema. (Questa non è "normalizzazione", come discusso in alcuni commenti.)

Do non passare a MyISAM; sta andando via.
Non preoccuparti ROW_FORMAT.

Sarà necessario modificare il codice per eseguire JOINe per gestire più righe anziché più colonne.


1

Utilizzo MySQL 5.6 su AWS RDS. Ho aggiornato di seguito nel gruppo di parametri.

innodb_file_per_table=1
innodb_file_format = Barracuda

Ho dovuto riavviare l'istanza database per rendere effettive le modifiche al gruppo di parametri.

Inoltre, ROW_FORMAT = COMPRESSED non era supportato. Ho usato DYNAMIC come sotto e ha funzionato bene.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8

1

La dimensione massima delle righe per una tabella InnoDB, che si applica ai dati archiviati localmente all'interno di una pagina di database, è leggermente inferiore alla metà di una pagina per 4KB, 8KB, 16KB e 32KB

Per pagine da 16 kb (impostazione predefinita), possiamo calcolare:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

Fondamentalmente, potresti massimizzare una riga con:

  • 11 campi varchar> 767 caratteri (latin1 = 1 byte per carattere) o
  • 11 campi varchar> 255 caratteri (utf-8 su mysql = 3 byte per carattere).

Ricorda, andrà in overflow a una pagina di overflow solo se il campo è> 767 byte. Se ci sono troppi campi di 767 byte, verrà interrotto (superando la max row_size). Non usuale con latin1 ma molto possibile con utf-8 se gli sviluppatori non stanno attenti.

In questo caso, penso che potresti portare innodb_page_size a 32kb.

in my.cnf:

innodb_page_size=32K

Riferimenti:


0

Ho anche riscontrato lo stesso problema. Risolvo il problema eseguendo il seguente sql:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Ma penso che dovresti sapere del Row Storage .
Esistono due tipi di colonne: colonne a lunghezza variabile (come i tipi VARCHAR, VARBINARY e BLOB e TEXT) e colonne a lunghezza fissa . Sono memorizzati in diversi tipi di pagine.

Le colonne a lunghezza variabile sono un'eccezione a questa regola. Le colonne come BLOB e VARCHAR che sono troppo lunghe per adattarsi a una pagina albero B vengono memorizzate su pagine disco allocate separatamente chiamate pagine di overflow. Chiamiamo tali colonne colonne fuori pagina. I valori di queste colonne sono memorizzati in elenchi collegati singolarmente di pagine di overflow e ciascuna di queste colonne ha il proprio elenco di una o più pagine di overflow. In alcuni casi, tutto o un prefisso del valore della colonna lunga viene memorizzato nell'albero B, per evitare di sprecare spazio di archiviazione ed eliminare la necessità di leggere una pagina separata.

e quando lo scopo dell'impostazione di ROW_FORMAT è

Quando una tabella viene creata con ROW_FORMAT = DYNAMIC o ROW_FORMAT = COMPRESSED, InnoDB può memorizzare valori lunghi di colonne di lunghezza variabile (per i tipi VARCHAR, VARBINARY e BLOB e TEXT) completamente fuori pagina, con il record di indice cluster contenente solo 20- puntatore byte alla pagina di overflow.

Vuoi saperne di più sui formati di riga DYNAMIC e COMPRESSED


0

Se ciò si verifica su un SELECT con molte colonne, la causa può essere che mysql sta creando una tabella temporanea. Se questa tabella è troppo grande per essere contenuta in memoria, utilizzerà il formato di tabella temporanea predefinito, che è InnoDB, per archiviarla su disco. In questo caso si applicano i limiti di dimensione di InnoDB.

Hai quindi 4 opzioni:

  1. modificare il limite di dimensione della riga innodb come indicato in un altro post, che richiede la reinizializzazione del server.
  2. modificare la query per includere meno colonne o evitare di creare una tabella temporanea (ad esempio rimuovendo le clausole order by e limit).
  3. cambiando max_heap_table_size in modo che sia grande in modo che il risultato si adatti alla memoria e non sia necessario che venga scritto su disco.
  4. cambia il formato della tabella temporanea predefinito in MYISAM, questo è quello che ho fatto. Modifica in my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

Riavvia mysql, la query funziona.


0

Ecco un semplice suggerimento per chiunque sia interessato:

Dopo l'aggiornamento da Debian 9 a Debian 10 con 10.3.17-MariaDB, ho alcuni errori dai database di Joomla:

[Avviso] InnoDB: impossibile aggiungere un campo fieldnella tabella database.tableperché dopo averlo aggiunto, la dimensione della riga è 8742, che è maggiore della dimensione massima consentita (8126) per un record sulla pagina foglia dell'indice.

Per ogni evenienza, ho impostato innodb_default_row_format = DYNAMIC in /etc/mysql/mariadb.conf.d/50-server.cnf (era comunque predefinito)

Quindi, ho usato phpmyadmin per eseguire "Optimize table" per tutte le tabelle nel database di Joomla. Penso che la ricreazione della tabella fatta da phpmyadmin nel processo abbia aiutato. Se ti capita di avere phpmyadmin installato, bastano pochi clic.


Se sei un utente Joomla, unisciti a noi su Joomla Stack Exchange: possiamo sempre utilizzare nuovi contributori.
mickmackusa
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.