如何优化我的 mysql 设置以更快地创建我的索引?

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 表(这可能只会为我节省几个小时?)

  • 我想要这个“按排序修复”吗?

Rol*_*DBA 6

对于初学者,我还不会触及缓冲区大小。你在问题中的尺寸太大了。

这是另一个观察结果:您有 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 表的混乱局面。

试一试 !!!