MySQL hängt vollständig, wenn `ALTER TABLE… ENABLE KEYS`

7

Ich weiß sehr wenig über Datenbankverwaltung, muss mich aber mit einigen sehr großen Tabellen auf meiner Site befassen.

Dieser Server verfügt über 64 GB RAM und Intel Core i7-3820 (4 x 3600 MHz). Das meiste von allem, was es tut, ist MySQL. Ich verwende halb MyISAM- und halb InnoDB-Tabellen.

Ich habe ein paar Tabellen in MyISAM mit Milliarden von Zeilen. Jeden Tag habe ich ein Skript, das Schlüssel deaktiviert, einige Millionen weitere Zeilen hinzufügt und dann Schlüssel wieder aktiviert. Dies führt dazu, ALTER TABLE... ENABLE KEYSdass der Server für einige Stunden angehalten wird. Keine Website, die MySQL verwendet, wird überhaupt geladen, obwohl sie überhaupt nicht auf die Tabellen zugreifen, die geändert werden.

Bitte teilen Sie mir auch mit, wie Sie die Datei my.cnf einrichten, um dieses Problem zu beheben und zu optimieren, damit diese Indizes so schnell wie möglich neu erstellt werden. Jemand sagte mir, ich solle die key_buffer_size erhöhen, aber ich bin mir nicht sicher, ob dies gut ist, da jeder eine andere Meinung zu haben scheint. Derzeit sieht es so aus:

[client]
port        = 3306
socket      = /var/lib/mysql/mysql.sock

[mysqld]
port = 3306
socket = /var/lib/mysql/mysql.sock
skip-external-locking
max_allowed_packet = 512M
table_open_cache = 1024
sort_buffer_size = 128M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 24G
thread_cache_size = 12
query_cache_size = 256M
thread_concurrency = 16
log-bin=mysql-bin
binlog_format=mixed
server-id   = 1
innodb_file_per_table = 1
table_cache = 1024
key_buffer = 256M
key_buffer_size = 12G
myisam_repair_threads = 4
big-tables
bind-address = 127.0.0.1
max_connections = 400
tmp_table_size = 4G
max_heap_table_size = 4G
log_bin = /backup/mysql-bin-logs/mysql-bin.log
expire_logs_days        = 10
max_binlog_size         = 100M
innodb_buffer_pool_size = 12G
local-infile=1
net_read_timeout = 1800
net_write_timeout = 1800


[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
local-infile=1

[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M
key_buffer = 256M

[mysqlhotcopy]
interactive-timeout

MySQL-Version

innodb_version 5.5.30
protocol_version 10
version 5.5.30-log
version_comment MySQL Community Server (GPL) by Remi
version_compile_machine x86_64
version_compile_os Linux

AKTUALISIEREN

Ich habe ein Kopfgeld angefangen. Ich habe einige der my.conf-Einstellungen geändert (auch in diesem Beitrag aktualisiert). Als ich dann versuchte, die Indizes für die große Tabelle neu zu erstellen, begann sie mit Repair with 8 threads(obwohl die Anzahl der Reparatur-Threads auf 4 festgelegt ist), und als ich sie einige Stunden später überprüfte, war derselbe Befehl aktiviert Repair with keycache, der sich jetzt dort befindet Sitzung. Irgendwie hat es sich von der Sortier- zur Keycache-Methode verschlechtert (ich habe keine Ahnung warum!)

Bitte helfen Sie mir, dies zu optimieren! Es soll jeden Tag laufen, dauert aber derzeit mehrere Tage, nur um ALTER TABLE... ENABLE KEYS.

Hier sind einige andere Variablen, nach denen ich gefragt wurde, die ich nicht verstehe, die Ihnen aber helfen könnten, mir zu helfen:

+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| key_cache_block_size | 1024  |
+----------------------+-------+
+-----------------+-------------+
| Variable_name   | Value       |
+-----------------+-------------+
| key_buffer_size | 12884901888 |
+-----------------+-------------+
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Key_blocks_unused | 0     |
+-------------------+-------+

AKTUALISIERUNG 2 (5/21)

Da ich dachte, es würde mein Problem lösen, habe ich mein Skript so geändert, dass die Tabelle vollständig abgeschnitten, alle Zeilen erneut eingefügt und die Indizes einzeln hinzugefügt werden. Anstatt Schlüssel zu deaktivieren, fügen Sie neue Zeilen hinzu und aktivieren Sie dann die Schlüssel.

Leider hat es nicht geholfen, da die Indexerstellung noch an geht repair with keycache.

Hier ist das Ergebnis von SHOW CREATE TABLE research_storage1:

CREATE TABLE `research_storage1` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `word1` mediumint(8) unsigned NOT NULL,
  `word2` mediumint(8) unsigned NOT NULL,
  `origyear` smallint(5) unsigned NOT NULL,
  `cat` tinyint(3) unsigned NOT NULL,
  `pibn` int(10) unsigned NOT NULL,
  `page` smallint(5) unsigned NOT NULL,
  `pos` smallint(5) unsigned NOT NULL,
  `num` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pibnpage` (`pibn`,`page`,`word2`,`word1`),
  KEY `word21pibn` (`word2`,`word1`,`pibn`,`num`),
  KEY `word12num` (`word1`,`word2`,`num`),
  KEY `cat1` (`cat`,`word1`),
  KEY `year1` (`origyear`,`word1`),
  KEY `catyear1` (`cat`,`origyear`,`word1`),
  KEY `pibn` (`pibn`,`word1`)
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin DATA DIRECTORY='/storage/researchdb/' INDEX DIRECTORY='/storage/researchdb/';

Ich habe auch diesen Befehl ausgeführt: SELECT data_length/power(1024,3) dat,index_length/power(1024,3) ndx FROM information_schema.tables WHERE table_schema='dbname' AND table_name='tablename'; Das Problem dabei ist jedoch, dass ich derzeit 2 Tabellen für diese Tabelle habe, eine, die abgeschnitten ist, und eine, die alle Daten, aber keine Indizes enthält (die ersteren werden durch die letzteren ersetzt, sobald die Indizes abgeschlossen sind ) ... der Grund dafür ist, dass ich die verdammten Indizes nicht erstellen kann (daher das Problem). Hier sind die Informationen für die abgeschnittene Tabelle und dann die Tabelle mit Daten, aber ohne Indizes:

+------+------------------------+
| dat  | ndx                    |
+------+------------------------+
|    0 | 0.00000095367431640625 |
+------+------------------------+
+-------------------+--------------------+
| dat               | ndx                |
+-------------------+--------------------+
| 51.61232269741595 | 27.559160232543945 |
+-------------------+--------------------+

Bitte beachten Sie auch, dass die Tabelle 10x größer ist, bevor alle Daten empfangen werden.

Alasdair
quelle
Können Sie die genaue Version von MySQL teilen, die Sie verwenden ( show variables like '%version%';)? Einige ziemlich alte Versionen haben große Fehler mit ENABLE KEYS. Es gibt auch einige Leckerbissen auf der Indexerstellung hier Das könnte helfen.
Nathan Jolly
OK, ich habe den Beitrag damit bearbeitet.
Alasdair
Wenn Sie das nächste Mal ausgeführt werden, führen Sie ALTER TABLE ... ENABLE KEYSbitte nur SHOW PROCESSLIST;die Ausgabe dieses Prozesses aus und veröffentlichen Sie sie.
RolandoMySQLDBA
Können Sie die Ausgabe der folgenden Anweisungen schreiben ( SHOW VARIABLES LIKE 'key_cache_block_size';, SHOW VARIABLES LIKE 'key_buffer_size';, SHOW GLOBAL STATUS LIKE '%Key_blocks_unused%'; )?
Cristian Porta
Ich habe den Hauptbeitrag mit dem neuesten aktualisiert.
Alasdair

Antworten:

3

Im Moment sind Sie in einer sehr glücklichen Lage. Mir ist aufgefallen, dass Sie big-tablesdefiniert haben. Dies verhindert, dass Fehler "Tabelle ist voll" auftreten. Warum ist das gut?

Immer wenn Sie den Status "Reparieren mit Schlüsselcache" erhalten, haben Sie keinen freien Speicherplatz für die Dateisortierung. Sort_buffer_size größer zu machen, ist nicht unbedingt die Antwort, da temporäre Tabellen sofort zu Datenträgerdateien werden.

Sie haben zwei Möglichkeiten

OPTION 1: Erhöhen Sie den Speicherplatz für Datadir

Das Datenvolumen, in dem sich /var/lib/mysql(oder was auch datadirimmer) befindet, bietet möglicherweise nicht genügend Platz, um eine materialisierte temporäre Tabelle auf der Festplatte unterzubringen. Ich würde vorschlagen, die Größe des Festplattenvolumens auf mindestens das Doppelte zu erhöhen.

DRAWBACK : Eine einmalige Wartung, um die Datenbank auf die größere Festplatte zu verschieben.

OPTION 2: Separate Festplatte für temporäre Tabellen

Möglicherweise sollte ein separates Datenträger-Volume eingerichtet werden, dessen einziger Lebenszweck darin besteht, temporäre Tabellen unterzubringen. Versuche dies

  • Schritt 01: Installieren Sie eine Festplatte mit der gleichen Größe wie die Heimat von datadir
  • Schritt 02: mkdir /tmptables
  • Schritt 03: Hängen Sie das neue Datenträger-Volume in den Ordner ein /tmptables
  • Schritt 04: chown mysql:mysql /tmptables
  • Schritt 05: Fügen Sie dies hinzu my.cnf
    • tmpdir=/tmptables
  • Schritt 06: service mysql restart

Sobald Sie die Festplatte erstellt und hinzugefügt haben tmpdir, sollten Sie mehr Spielraum haben.

DRAWBACK : Übertragen des Inhalts der temporären Tabellen für bestimmte SQL-Befehle (z. B. DDL) von /tmptableszurück zur Startseite von datadir.

UPDATE 2013-05-21 00:10 EDT

Sie haben einfach nicht genug Speicher. Alle Kerne der Welt können MyISAM nicht helfen.

VORSCHLAG 1: Kürzen Sie Ihre Schlüssel

Ich kann an den Schlüsseln erkennen, dass Sie versuchen, alle Daten aus den Indizes abzurufen und die Tabelle nicht zu berühren. Alles schön und gut, wenn es nicht für die Milliarden von Reihen wäre.

Hier ist etwas zu beachten: Kürzen Sie die Schlüssel für jeden Index

CREATE TABLE `research_storage1` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `word1` mediumint(8) unsigned NOT NULL,
  `word2` mediumint(8) unsigned NOT NULL,
  `origyear` smallint(5) unsigned NOT NULL,
  `cat` tinyint(3) unsigned NOT NULL,
  `pibn` int(10) unsigned NOT NULL,
  `page` smallint(5) unsigned NOT NULL,
  `pos` smallint(5) unsigned NOT NULL,
  `num` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pibnpage` (`pibn`,`page`),
  KEY `word21` (`word2`,`word1`),
  KEY `cat1` (`cat`,`word1`),
  KEY `year1` (`origyear`,`word1`),
  KEY `catyear1` (`cat`,`origyear`),
  KEY `pibn` (`pibn`,`word1`)
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin
DATA DIRECTORY='/storage/researchdb/'
INDEX DIRECTORY='/storage/researchdb/';

VORSCHLAG 2: Verwenden Sie nicht mehr ALTER TABLE...ENABLE KEYS;

Sie sollten versuchen, MyISAM ohne Verwendung in eine neue Tabelle zu importieren ENABLE KEYS.

CREATE TABLE `research_storagenew` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `word1` mediumint(8) unsigned NOT NULL,
  `word2` mediumint(8) unsigned NOT NULL,
  `origyear` smallint(5) unsigned NOT NULL,
  `cat` tinyint(3) unsigned NOT NULL,
  `pibn` int(10) unsigned NOT NULL,
  `page` smallint(5) unsigned NOT NULL,
  `pos` smallint(5) unsigned NOT NULL,
  `num` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pibnpage` (`pibn`,`page`,`word2`,`word1`),
  KEY `word21pibn` (`word2`,`word1`,`pibn`,`num`),
  KEY `word12num` (`word1`,`word2`,`num`),
  KEY `cat1` (`cat`,`word1`),
  KEY `year1` (`origyear`,`word1`),
  KEY `catyear1` (`cat`,`origyear`,`word1`),
  KEY `pibn` (`pibn`,`word1`)
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin
DATA DIRECTORY='/storage/researchdb/'
INDEX DIRECTORY='/storage/researchdb/';
INSERT INTO `research_storagenew` SELECT * FROM `research_storage1`;
DROP TABLE `research_storage1`;
ALTER TABLE `research_storagenew` RENAME `research_storage1`;

ZUSAMMENFASSUNG

Schauen Sie sich die Tabellendefinition noch einmal an. Es gibt 18 Bytes für einen Indexeintrag nur für den pibnpageIndex. Das sind 18 G pro Milliarde Zeilen. Gleiches gilt für word21pibn. Sie haben einfach nicht genug Platz. Es ist unbedingt erforderlich, einen meiner neuesten Vorschläge zu versuchen, um die Notwendigkeit zu umgehen, alle diese Schlüssel zu sortieren.

UPDATE 2013-05-22 12:15 EDT

Du hast gefragt

Über das Kürzen der Tasten: Welche Art von Leistungseinbußen wird dies bewirken? Sprechen wir doppelt so lange, 10x so lang, 1000x so lang?

Ich kann nicht sicher sagen, welche Auswirkungen die Laufzeit dort haben wird. Ich kann jedoch Folgendes sagen: Möglicherweise gibt es zusätzliche Festplatten-E / A, da die Indizes nicht mehr die erforderlichen Spalteninformationen enthalten. Abfragen müssen nicht an die .MYDDatei weitergeleitet werden, um zusätzliche Spalteninformationen abzurufen. Bitte beachten Sie, dass MyISAM für häufig gelesene Abfragen geeignet ist.

Die einzige Einstellung, die ich weiter empfehlen kann, wenn es während starker Leseperioden mitten am Tag INSERTs und DELETEs geben soll, wäre die gleichzeitige Aktivierung von INSERTs.

[mysqld]
concurrent_insert=1

Dies ermöglicht INSERTs in MyISAM, ohne nach freien Blöcken in der Tabelle zu suchen. Dadurch kann der Tisch etwas schneller wachsen.

Was die Wartung angeht, müssen Sie sich SUGGESTION #2nicht so sehr ALTER TABLE ... ENABLE KEYS;auf einen so aufgeblähten Tisch verlassen. Vielleicht sollten Sie daran denken, /storage/researchdb/auf SSD umzusteigen.

RolandoMySQLDBA
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Paul White 9