Dol*_*cci 3 mysql myisam index unique-constraint
我有一台运行 Ubuntu 10.04 的服务器,并通过包安装了 Mysql 5.1x。该系统有 128GB 内存,8 个内核,并有 4TB 的可用空间,用于存储 Mysql 和 Mysql tmp。
我有一个这样的 MyISAM:
CREATE TABLE `data_store` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uniqname` varchar(150) NOT NULL,
`data` blob,
PRIMARY KEY (`id`)
) ENGINE=MyISAM CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)
我插入了 8 亿条记录(插入前大约有 350GB 数据),然后尝试添加以下索引:
ALTER TABLE data_store DISABLE KEYS;
ALTER TABLE data_store ADD INDEX uniqname_index (uniqname);
ALTER TABLE data_store ENABLE KEYS;
Run Code Online (Sandbox Code Playgroud)
(关于DISABLE KEYS
命令,我看到在其他地方建议在插入数据之前使用,并且由于该命令从未使用过ENABLE KEYS
,我认为它对我没有用处。我主要只是在我对我的描述中进行了详尽的描述我在做。)
当我开始索引作业时,显示的第一个状态SHOW PROCESSLIST
是“复制到 tmp 表”。
几个小时后,我检查了 bac,即使在 24 小时后,状态仍保留在“使用密钥缓存修复”消息上。我尝试在稍旧的服务器上运行该作业,3 天后,它仍然保持“使用密钥缓存修复”状态。因此,我在这台较新的机器上取消了 create-index 命令。
我读过“使用密钥缓存修复”可能非常慢,并且在许多情况下首选“通过排序修复”。
根据一些 Stack Exchange 和在线随机帖子,我在 Mysql 服务器中添加了以下设置:
myisam_sort_buffer_size = 80G
bulk_insert_buffer_size = 80G
myisam_repair_threads = 8
max_heap_table_size = 20G
myisam_max_sort_file_size = 500G
tmp_table_size = 20G
key_buffer_size = 20G
sort_buffer_size = 20G
join_buffer_size = 20G
Run Code Online (Sandbox Code Playgroud)
我重新启动了作业,同样的过程再次发生(复制到 tmp 文件,然后通过密钥缓存修复)。
在我杀死作业后,我注意到在 mysql/error.log 中,有一条消息“myisam_sort_buffer_size 太小”。这发生在当天早些时候,而不是我结束工作的时候。
问题
我会以这种错误的方式吗?我只是希望能够通过某个键(uniqname)快速查找我的数据。
从我的表开始,从头开始添加索引,使用该DISABLE KEYS
命令,插入我的 800 百万条记录,然后再重新开始有什么好处ENABLE KEYS
吗?我在别处读到这可以防止复制 tmp 表(这可能只会为我节省几个小时?)
我想要这个“按排序修复”吗?
对于初学者,我还不会触及缓冲区大小。你在问题中的尺寸太大了。
这是另一个观察结果:您有 BLOB 数据。哎哟,你的临时表会很快吃掉空间。你可以这样做:
通过将此行添加到 /etc/fstab 创建一个名为 /var/tmpfs 的 32GB RAM 磁盘
none /var/tmpfs tmpfs defaults,size=32g 1 2
Run Code Online (Sandbox Code Playgroud)
接下来,创建一个名为 /mysqltmp 的文件夹并在其上挂载 RAM 磁盘
mkdir /mysqltmp
chown mysql:mysql /mysqltmp
mount /mysqltmp /var/tmpfs
Run Code Online (Sandbox Code Playgroud)
将此添加到 my.cnf 并重新启动 mysql
[mysqld]
tmpdir=/mysqltmp
Run Code Online (Sandbox Code Playgroud)
现在,通过 DDL 生成的任何 tmp 表都位于 RAM 磁盘中。
这是另一个观察结果:为什么不创建一个单独的表,使 BLOB 数据远离唯一名称?
CREATE TABLE `data_store_name` SELECT id,uniqname FROM `data_store` WHERE 1=2;
ALTER TABLE `data_store_name` ADD PRIMARY KEY (id);
ALTER TABLE `data_store_name` ADD UNIQUE KEY (uniqname);
ALTER TABLE `data_store_name` ADD INDEX name_id_ndx (uniqname,id);
INSERT INTO `data_store_name` SELECT id,uniqname FROM `data_store`;
Run Code Online (Sandbox Code Playgroud)
这将防止在索引时移动 BLOB 数据。
从这里开始,您必须始终使用其名称加入 data_store,如下所示:
SELECT
A.uniqname,B.data
FROM
(SELECT * FROM data_store_name WHERE uniqname = 'mydataname') A
LEFT JOIN
data_store B USING (id)
;
Run Code Online (Sandbox Code Playgroud)
进行这些更改将避免处理密钥缓存、RAM 磁盘和 tmp 表的混乱局面。
试一试 !!!