Come aggiungere una colonna alla grande tabella in MySQL


13

Sono uno sviluppatore di PHP, quindi non essere severo. Ho un grande tavolo ~ 5,5 gb di discarica. Il nostro PM ha deciso di creare una nuova colonna per eseguire nuove funzionalità. Table è InnoDB, quindi quello che ho provato:

  1. Modifica la tabella sullo schermo con il blocco della tabella. Ci sono voluti circa 30 ore e niente. Quindi l'ho appena fermato. Innanzitutto ho fatto un errore perché non ho terminato tutte le transazioni, ma la seconda volta non è stato un multilock. Lo stato era copy to tmp table.

  2. Dato che devo applicare anche il partizionamento per questa tabella, decidiamo di creare un dump, rinominare e creare una tabella con lo stesso nome e la nuova struttura. Ma la discarica sta facendo una copia rigorosa (almeno non ho trovato qualcos'altro). Quindi ho aggiunto per scaricare una nuova colonna sede interrogarla. Ma iniziarono alcuni strani errori. Credo che sia stato causato da charset. La tabella in utf-8 e il file sono diventati us-ascii dopo sed. Quindi ho ricevuto errori (comando sconosciuto '\' ') sul 30% dei dati. Quindi anche questo è un brutto modo.

Quali sono le altre opzioni per ottenere questo risultato e velocizzare le prestazioni (posso farlo con lo script php, ma ci vorranno anni). Quale sarà la prestazione INSERT SELECTin questo caso.

Grazie per qualsiasi anticipo.

Risposte:


12

Usa MySQL Workbench . È possibile fare clic con il pulsante destro del mouse su una tabella e selezionare "Invia a SQL Editor" -> "Crea istruzione". In questo modo nessuna tabella "proprietà" verrà dimenticata da aggiungere (incluso CHARSETo COLLATE).
Con questa enorme quantità di dati, consiglierei di ripulire la tabella o la struttura dei dati che usi (un buon DBA è utile). Se non è possibile:

  • rinominare la tabella ( ALTER) e crearne una nuova con lo CREATEscript che si ottiene da Workbench. Puoi anche estendere quella query con il nuovo campo di cui hai bisogno
  • BULK LOAD i dati dalla vecchia tabella a quella nuova:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    In questo modo si evita l'indicizzazione / etc per eseguire record per record. L '"aggiornamento" della tabella sarà comunque lento (poiché la quantità di dati è enorme) ma questo è il modo più veloce che mi viene in mente.

    MODIFICA: leggi questo articolo per ottenere dettagli sui comandi utilizzati nella query di esempio sopra;)

Le mie opzioni vanno bene. E ho ottenuto SET NAMES utf8e COLLATION.Ma meh idk perché il 30% dei dati danneggiati dopo sed. Penso che il carico di massa sarà il più veloce, ma forse esiste qualcosa in più che mi manca. Grazie Marco
ineersa il

1
La corruzione dei dati @ineersa può avere molte ragioni: ad esempio, hai aperto il file con un editor che non supporta tutti i caratteri e lo hai salvato. Oppure, il modo in cui si tenta di importare dal dump corrompe i dati (è errato e non è in grado di leggere correttamente il file). Oppure, lo stesso ragazzo può identificare parte di alcuni dati come un'espressione (ad esempio "james \ robin" == "\ r" come espressione) o comando, ecc. Ecco perché non consiglio mai di usare il dump, nemmeno con lo strumento di dump di dati binari solo, nemmeno con dev.mysql.com/doc/refman/5.6/en/mysqldump.html (o BCP per MS SQL Server). Va storto fin troppe volte ...

sì, ho provato con hex-blob. non aiuta. Inoltre, subito dopo aver usato sed mysql identifichi \ 'come comando in alcuni nomi (non in tutti). È strano e pieno di bug. Proverò a caricare alla rinfusa stasera. Spero che sarà fatto almeno tra 10-15 ore.
ineersa,

@ineersa spero che sia così. puoi anche provare ad aggiungere solo una parte dei dati, diciamo il 10% per vedere quanto tempo ci vuole e avere una stima per l'intera transazione. Sarà una stima molto approssimativa, tuttavia, le cose possono andare piano se cache / memoria / qualunque cosa venga riempita / sovraccaricata.

1
Grazie Marco. Ha funzionato alla grande. Ancora più veloce del ripristino dalla discarica. Ci sono voluti ~ 5 ore.
ineersa,

5

La tua idea sed è un metodo decente, ma senza gli errori o il comando che hai eseguito, non possiamo aiutarti.

Tuttavia, un metodo ben noto per apportare modifiche online a tabelle di grandi dimensioni è pt-online-schema-change . Il semplice aspetto negativo di ciò che fa questo strumento è copiato dalla documentazione:

pt-online-schema-change funziona creando una copia vuota della tabella da modificare, modificandola come desiderato e quindi copiando le righe dalla tabella originale nella nuova tabella. Quando la copia è completa, sposta la tabella originale e la sostituisce con quella nuova. Per impostazione predefinita, rilascia anche la tabella originale.

Il completamento di questo metodo potrebbe richiedere del tempo, ma durante il processo la tabella originale sarà completamente utilizzabile.


Proverò ad effettuare il caricamento di massa più tardi stasera. Se non funziona sarà probabilmente necessario questo strumento. Gli errori sono causati dall'invio di alcuni simboli dopo l'utilizzo di sed come comandi. Ad esempio 'D\'agostini'causerà un errore unknown command '\''. Ma non sempre, come nel 30% dei casi. È strano e pieno di bug. Lo stesso vale anche con i dump di blob esadecimali. Grazie Derek.
ineersa,

4

alter table add column, algorithm=inplace, lock=none modificherà una tabella MySQL 5.6 senza copiare la tabella e senza bloccare l'impatto.

Appena testato questo ieri, la massa ha inserito 70 KB di righe in una tabella di partizioni di 280 KB di riga 7, 10 KB di righe in ciascuna partizione, con 5 secondi di sospensione in mezzo per consentire un altro throughput.

Iniziarono gli inserti di massa, quindi in una sessione separata iniziarono la alterdichiarazione online sopra in MySQL Workbench, il altertermine prima degli inserimenti, furono aggiunte due nuove colonne e nessuna riga risultò dall'alterazione, nel senso che MySQL non copiava alcuna riga.


1
Perché questa risposta non ottiene più voti? Non funziona?
fguillen,

1

Attualmente, l'opzione migliore per modificare tabelle enormi è probabilmente https://github.com/github/gh-ost

gh-ost è una soluzione di migrazione dello schema online senza trigger per MySQL. È testabile e offre supporto, controllo dinamico / riconfigurazione, controllo e numerosi vantaggi operativi.

gh-ost produce un carico di lavoro leggero sul master durante la migrazione, disaccoppiato dal carico di lavoro esistente sulla tabella migrata.

È stato progettato sulla base di anni di esperienza con soluzioni esistenti e cambia il paradigma delle migrazioni di tabelle.


1

Penso che Mydumper / Myloader sia un buon strumento per operazioni come questa: migliora ogni giorno. Puoi utilizzare le tue CPU e caricare i dati in parallelo: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and- usabilità-caratteristiche /

Sono riuscito a caricare centinaia di gigabyte di tabelle MySQL in poche ore.

Ora, quando si tratta di aggiungere una nuova colonna, è difficile in quanto MySQL copia l'intera tabella TMPnell'area di memoria con ALTER TABLE...Sebbene MySQL 5.6 affermi che può apportare modifiche allo schema online, non sono riuscito a eseguirle online per tabelle enormi senza blocco contesa ancora.


-2

ho appena avuto lo stesso problema. Un po 'di soluzione:

CREATE TABLE new_table SELEZIONA * DA oldtable;

ELIMINA DA new_table

ALTER TABLE new_table AGGIUNGI COLONNA new_column int (11);

INSERISCI in new_table seleziona *, 0 da old_table

drop table old_table; rinomina tabella new_table TO old_table;


Perché non aggiungere semplicemente una clausola where all'istruzione create table in modo che non selezioni alcun dato? Anche troncare la tabella sarebbe più efficiente della cancellazione dei dati
Joe W,

perché eliminare, quando è necessario inserire più tardi, di nuovo. Può definire default = 0 su ADD COLUMN stesso.
user195280
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.