Ala*_*air 8 mysql myisam index
我对数据库管理知之甚少,但我必须处理我网站上的一些非常大的表。
该服务器具有 64GB 内存和 Intel Core i7-3820 (4 x 3600 MHz)。它所做的大部分事情都是 MySQL。我使用一半 MyISAM 和一半 InnoDB 表。
我在 MyISAM 中有几个表,有数十亿行。每天我都有一个脚本禁用键,再添加几百万行,然后再次启用键。这ALTER TABLE... ENABLE KEYS
会导致服务器基本上停止几个小时。任何使用 MySQL 的网站都不会加载,即使它们根本不访问正在更改的表。
还请告诉我如何设置 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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
更新
我已经开始赏金了。我更改了一些 my.conf 设置(也在这篇文章中更新)。然后,当我尝试在大表上重建索引时,它开始时Repair with 8 threads
(即使修复线程的数量设置为 4),然后当我几小时后检查它时,相同的命令打开了Repair with keycache
,现在是它所在的位置坐着。所以不知何故它从 sort 降级为 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 |
+-------------------+-------+
Run Code Online (Sandbox Code Playgroud)
更新日期 2 (5/21)
认为它会解决我的问题,我已经更改了我的脚本以完全截断表,重新插入所有行,并一次添加一个索引。不是禁用密钥,而是添加新行然后启用密钥。
不幸的是它没有帮助,因为索引创建仍然转到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/';
Run Code Online (Sandbox Code Playgroud)
我也运行了这个命令:
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 |
+-------------------+--------------------+
Run Code Online (Sandbox Code Playgroud)
另请注意,在接收到所有数据之前,该表将比此大 10 倍。
现在,你处于一个非常幸运的位置。我注意到你已经big-tables
定义了。这可以防止您遇到“表已满”错误。为什么这样好呢?
每当您获得“使用 Keycache 修复”状态时,您就没有可用空间来进行文件排序。增大 sort_buffer_size 不一定是答案,因为临时表会立即变成磁盘文件。
你有两个选择
所在的数据卷/var/lib/mysql
(或任何datadir
内容)可能没有足够的空间来容纳磁盘上的物化临时表。我建议将磁盘卷的大小增加到至少两倍。
缺点:将数据库移动到更大的磁盘的一次性维护。
也许应该设置一个单独的磁盘卷,其唯一的目的是容纳临时表。尝试这个
datadir
mkdir /tmptables
/tmptables
chown mysql:mysql /tmptables
my.cnf
tmpdir=/tmptables
service mysql restart
一旦你制作了磁盘并添加了tmpdir
,你应该有更多的活动空间。
缺点:将临时表内容从某些 SQL 命令(例如 DDL)/tmptables
的主目录传输回。datadir
你根本就没有足够的内存。世界上所有的核心都无法帮助MyISAM。
我可以从键中看出您正在尝试从索引中检索所有数据并避免接触表。如果不是数十亿行的话,一切都很好。
这里有一些值得考虑的事情:缩短每个索引的键
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/';
Run Code Online (Sandbox Code Playgroud)
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`;
Run Code Online (Sandbox Code Playgroud)
再看一下表定义。仅索引上的索引条目就有 18 个字节pibnpage
。即每十亿行 18G。同样适用于word21pibn
. 你只是没有足够的空间。必须尝试我的最新建议之一来绕过对所有这些键进行排序的需要。
你问
关于缩短按键:这会导致什么样的性能影响?我们所说的时间是两倍、十倍还是 1000 倍?
我无法确定会对运行时间产生什么影响。不过,我可以这样说:可能会有一些额外的磁盘 I/O,因为索引将不再包含所需的列信息。查询不必转向.MYD
文件来检索其他列信息。请记住,MyISAM 适合重读查询。
如果在一天中的重读期间应该有 INSERT 和 DELETE,我可以进一步建议的唯一调整是启用并发 INSERT。
[mysqld]
concurrent_insert=1
Run Code Online (Sandbox Code Playgroud)
这将允许 INSERT 到 MyISAM 中,而无需交叉检查表中的空闲块。这可能会使表增长得更快一些。
就维护而言,您必须使用SUGGESTION #2
,而不是过分依赖ALTER TABLE ... ENABLE KEYS;
如此臃肿的表。也许您应该考虑转向/storage/researchdb/
SSD。