MySQL 慢写

Ron*_*nn0 8 mysql innodb

插入下表最多需要 70 秒才能完成:

CREATE TABLE IF NOT EXISTS `productsCategories` (
  `categoriesId` int(11) NOT NULL,
  `productsId` int(11) NOT NULL,
  PRIMARY KEY (`categoriesId`,`productsId`),
  KEY `categoriesId` (`categoriesId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

表中有大约 100,000 行,占用了 7MB 磁盘空间。

MySQL 中是否有一些设置可以提高写入性能?

我的my.cnf文件如下:

log-slow-queries="/var/log/mysql/slow-query.log"
long_query_time=1 
log-queries-not-using-indexes

innodb_buffer_pool_size=4G
innodb_log_buffer_size=4M
innodb_flush_log_at_trx_commit=2
innodb_thread_concurrency=8
innodb_flush_method=O_DIRECT

query_cache_size = 6G
key_buffer_size = 284M
query_cache_limit = 1024M
thread_cache_size = 128
table_cache = 12800

sort_buffer_size=2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M

read_buffer_size=128K

open_files_limit               = 1000
table_definition_cache         = 1024
table_open_cache               = 6000

max_heap_table_size=512M
tmp_table_size=4096M

max_connections=1000

thread_concurrency = 24
Run Code Online (Sandbox Code Playgroud)

这是硬件设置:

  • 戴尔 R710
  • RAID10
  • 48G内存

鉴于此硬件,我不希望问题成为硬件瓶颈。

Rol*_*DBA 16

观察#1

首先吸引我的是表格结构

CREATE TABLE IF NOT EXISTS `productsCategories` (
  `categoriesId` int(11) NOT NULL,
  `productsId` int(11) NOT NULL,
  PRIMARY KEY (`categoriesId`,`productsId`),
  KEY `categoriesId` (`categoriesId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

请注意categoriesId索引和 PRIMARY KEY 从同一列开始。它是一个冗余索引。由于这个表是 InnoDB,categoriesId索引是多余的还有一个原因:所有二级索引都包含到 gen_clust_index 的键(又名聚集索引;看看gen_clust_index 在 mysql 中是做什么用的?

如果您删除categoriesId索引

ALTER TABLE productsCategories DROP INDEX categoriesId;
Run Code Online (Sandbox Code Playgroud)

这将显着改善 INSERT 因为不必进行额外的二级和聚集索引维护。

观察#2

如果您正在执行任何批量插入操作,则需要一个大批量插入缓冲区

请参阅我过去的帖子:

观察 #3

你的日志文件太小了!!!它应该是 InnoDB 缓冲池的 25%,在您的情况下应该是 1G。请参阅我关于如何调整 InnoDB 日志文件大小的帖子

观察 #4

请不要设置 innodb_thread_concurrency !!!我在 Percona Live NYC 学到了第一手的经验,不要管那个环境。它在 MySQL 5.5、MySQL 5.1 InnoDB 插件和 Percona Server 5.1+ 中默认禁用。

观察 #5

您需要使用 innodb_file_per_table。如果禁用此功能,我会使 ibdata1 上的文件维护成为一场噩梦。请阅读我关于如何清理 InnoDB 以实现这一点的帖子

观察 #6

如果您使用 MySQL 5.5 或 Percona Server,则必须设置某些选项以使 InnoDB 使用多 CPU/多核。请参阅我关于这些设置的帖子

观察 #7

你有innodb_log_buffer_size=4M。默认为 8M。这将导致刷新重做日志的次数增加两倍。这也会抵消你的innodb_flush_log_at_trx_commit=2设置。请设置为32M。另外,请参阅innodb_log_buffer_size 上的 MySQL 文档

根据这些观察,请添加或替换以下设置:

[mysqld]
innodb_thread_concurrency = 0
innodb_read_io_threads = 64
innodb_write_io_threads = 64
innodb_io_capacity = 5000
innodb_file_per_table
innodb_log_file_size=1G
innodb_log_buffer_size=1G
bulk_insert_buffer_size = 256M
Run Code Online (Sandbox Code Playgroud)

  • `query_cache_size` 也是巨大的。每个插入都需要最多 6GB 的缓存来刷新。 (2认同)