MySQL慢写


8

插入下表最多需要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;

该表中大约有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

这是硬件设置:

  • 戴尔R710
  • RAID10
  • 48G内存

有了这种硬件,我预计问题不会成为硬件瓶颈。


您可以提供一些客观数据吗?日志,您的测试/基准测试方法和结果,诸如此类?
womble

您想看哪种日志?我唯一知道为什么要花这么长时间的是在de mtop中。我会测试将表更改为myisam表,更高的内存限制,更高的线程。
Ronn0 2012年

改善mysql的最佳设置是切换到postgres大声笑
Antony Gibbs

thread_concurrency = 24无效...您可以抛弃该行
Antony Gibbs

Answers:


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;

请注意,categoriesId索引和PRIMARY KEY从同一列开始。这是一个冗余索引。由于此表是InnoDB,因此categoriesId索引的冗余是另一个原因:所有二级索引都包含gen_clust_index的键(也称为集群索引;请参阅mysql中gen_clust_index的作用是什么?

如果您使用删除categoriesId索引

ALTER TABLE productsCategories DROP INDEX categoriesId;

这将大大提高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

哇谢谢!我确实打印了所有点并立即进行处理,并将其保存在大脑中以在将来帮助其他人。非常感谢!
Ronn0

2
query_cache_size也是巨大的。每个插入将需要最多6GB的缓存来刷新。
亚伦·布朗

@AaronBrown我同意。我在《高性能MySQL》一书中读到,InnoDB使用查询缓存中InnoDB表上的事务ID进行繁琐的工作,这使得使用查询缓存有点不必要,更不用说它很慢了。实际上,MySQL 4.1已禁用InnoDB的查询缓存。
RolandoMySQLDBA 2012年

我认为查询缓存与存储引擎完全分开。它基本上通过迫使所有内容都经过并扫描查询缓存以使查询无效来序列化所有写操作。我从来没有找到用例,它总是引起问题。
亚伦·布朗

再增加一件事:query_cache_size = 6G <-这完全是荒谬的。通常最好禁用查询缓存,并且确保缓存不应大于32M或64M。维护6G查询缓存的开销肯定会损害性能。
加文·托威

0

您应该检查innodb_log_file_size,默认设置为5M,对于写密集型设置来说这是相当低的。考虑将其设置为100M。您必须删除旧ib_logfile*文件才能使用新设置启动数据库。在数据库服务器运行时,请不要删除日志文件,您必须先将其停止。可能您应该首先备份旧的日志文件,而不仅仅是删除它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.