web-dev-qa-db-ja.com

MySQLが「ALTER TABLE ... ENABLE KEYS」のときに完全にハングする

データベース管理についてはほとんど知りませんが、自分のサイトで非常に大きなテーブルを処理する必要があります。

このサーバーには64 GBのRAMおよびIntel Core i7-3820(4 x 3600 MHz)が搭載されています。サーバーが実行するほとんどすべての作業はMySQLです。MyISAMテーブルとInnoDBテーブルの半分を使用しています。

MyISAMには数十億行のテーブルがいくつかあります。毎日、キーを無効にし、数百万行を追加して、キーを再度有効にするスクリプトがあります。 ALTER TABLE... ENABLE KEYSにより、サーバーは基本的に数時間停止します。 MySQLを使用するWebサイトは、変更されるテーブルにまったくアクセスしていなくても、まったく読み込まれません。

My.cnfファイルを設定してこの問題を修正し、これらのインデックスをできるだけ早く再構築するために最適化する方法についても教えてください。誰かがkey_buffer_sizeを増やすように私に言ったが、誰もが異なる意見を持っているようであるので、これが良いかどうかわかりません。現在、このように見えます:

[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バージョン

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

[〜#〜]更新[〜#〜]

賞金を獲得しました。 my.conf設定の一部を変更しました(この投稿でも更新されています)。次に、大きなテーブルでインデックスを再構築しようとすると、(修復スレッドの数が4に設定されている場合でも)Repair with 8 threadsで始まり、数時間後に同じコマンドがRepair with keycacheで確認されました。座っているところ。どういうわけか、それはソートからキーキャッシュメソッドに低下しました(私はなぜか分かりません!)

これを最適化するのを手伝ってください!それは毎日実行することになっていますが、現在ALTER TABLE... ENABLE KEYSだけで数日かかります。

ここに私が尋ねられた他のいくつかの変数があります、私は理解していませんが、あなたが私を助けるのを助けるかもしれません:

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

PDATEDATE 2(5/21)

問題を解決できると思い、スクリプトを変更してテーブルを完全に切り捨て、すべての行を再挿入し、一度に1つずつインデックスを追加しました。キーを無効にする代わりに、新しい行を追加してからキーを有効にします。

残念ながら、インデックスの作成はrepair with keycacheで行われるため、役に立ちませんでした。

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/';

私はこのコマンドも実行しました: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';しかし、これに関する問題は、現在このテーブルに2つのテーブルがあり、1つは切り捨てられ、1つはすべてのデータを含みますがインデックスはありません(前者は置き換えられます)。後者の場合、インデックスが完成すると)...理由は、私がいまいましいインデックスを作成できないためです(そのため、問題が発生します)。以下は、切り捨てられたテーブルの情報であり、データのあるテーブルでインデックスはありません。

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

すべてのデータが受信される前に、テーブルはこれよりも10倍大きくなることにも注意してください。

7
Alasdair

現在、あなたは非常に幸運な立場にいます。 big-tables が定義されていることに気づきました。これにより、「テーブルがいっぱいです」エラーが発生するのを防ぎます。なぜこれが良いのですか?

「Repair With Keycache」というステータスが表示されると、ファイルの並べ替えを行うための空き容量がなくなります。 temp_tablesはすぐにディスクファイルになるため、sort_buffer_sizeを大きくしても必ずしもその答えは得られません。

2つのオプションがあります

オプション#1: datadir のディスク容量を増やす

/var/lib/mysql(または datadir が存在するデータボリューム)が存在するデータボリュームには、ディスク上にマテリアライズされた一時テーブルを格納するための十分なスペースがない可能性があります。ディスクボリュームのサイズを、少なくとも2倍にすることをお勧めします。

[〜#〜] drawback [〜#〜]:データベースをより大きいディスクに移動するための1回限りのメンテナンス。

オプション#2:一時テーブル用の別のディスク

おそらく、一時テーブルを格納することだけが目的である別のディスクボリュームを設定する必要があります。これを試して

  • ステップ01: datadir のホームと同じサイズのディスクをインストールします
  • ステップ02:mkdir /tmptables
  • 手順03:新しいディスクボリュームをフォルダー/tmptablesにマウントします
  • ステップ04:chown mysql:mysql /tmptables
  • ステップ05:これをmy.cnf に追加します
    • tmpdir=/tmptables
  • ステップ06:service mysql restart

ディスクを作成して tmpdir を追加すると、エルボースペースが増えるはずです。

[〜#〜] drawback [〜#〜]:一時テーブルの内容を/tmptablesから datadirのホームに転送 特定のSQLコマンド(DDLなど)の場合。

2013-05-21 00:10 EDT更新

十分なメモリがありません。世界のすべてのコアはMyISAMを助けることはできません。

提案#1:キーを短くする

キーから、インデックスからすべてのデータを取得しようとしていることと、テーブルに触れないようにすることができます。何十億もの行に対応できなかったとしても、順調です。

ここで検討する価値があります:各インデックスのキーを短くする

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/';

提案#2:ALTER TABLE...ENABLE KEYS;の使用をやめる

MyISAMを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`;

概要

テーブル定義をもう一度見てください。 pibnpageインデックスのみのインデックスエントリには18バイトがあります。これは、10億行あたり18Gです。同じことがWord21pibnにも当てはまります。十分なスペースがありません。これらすべてのキーをソートする必要を回避するために、私の最新の提案の1つを試すことが不可欠です。

UPDATE 2013-05-22 12:15 EDT

あなたが尋ねた

ただし、キーの短縮については、どのようなパフォーマンスヒットが発生しますか? 2倍の長さ、10倍の長さ、1000倍の長さですか。

実行時間にどのような影響があるかは、はっきりとは言えません。ただし、私はこれを言うことができます:インデックスには必要な列情報が含まれなくなるため、追加のディスクI/Oが発生する場合があります。クエリは、追加の列情報を取得するために.MYDファイルを参照する必要はありません。 MyISAMは読み取りの多いクエリに適していることに注意してください。

読み込みが多い期間の1日の途中でINSERTとDELETEが行われると思われる場合に推奨できる唯一のチューニングは、同時INSERTを有効にすることです。

[mysqld]
concurrent_insert=1

これにより、テーブル内の空きブロックをクロスチェックすることなくMyISAMへのINSERTが可能になります。これにより、テーブルの成長が少し速くなる場合があります。

メンテナンスに関しては、このような肥大したテーブルのSUGGESTION #2にあまり依存しないように、ALTER TABLE ... ENABLE KEYS;を使用する必要があります。おそらく、/storage/researchdb/をSSDに移動することを検討する必要があります。

3
RolandoMySQLDBA