【问题标题】:mysql performance issues on large tables with insert带有插入的大表上的mysql性能问题
【发布时间】:2015-03-09 19:29:26
【问题描述】:

我们有一个具有 8GB RAM 和 PHP5.3 和 MySQL 5.1 的专用服务器

最多有大约 500 个并发连接,每个连接使用用户数据对较小的表执行 1-2 次 SELECT 查询,然后在大表 transactions 中执行 INSERT。选择查询不需要太多,我们在每个查询之间添加了监控以查看每个查询的响应时间,并且从来没有问题。

我们在代码中添加了跟踪功能,有时会导致一些简单的 INSERT 查询需要 14-15 秒。下面列出的这个查询有时需要 14 秒、有时 6 秒、有时 0.2 秒或更短。可能是什么问题?

有时会返回这些巨大延迟的 PHP 代码:

$starT = microtime(true);
echo '&timestampTS_02='.(microtime(true) - $startT);
mysqli_query($GLOBALS['con'],"INSERT INTO `transactions` (`id`,`data`) VALUES('id','some_data')") or die(mysqli_error($GLOBALS['con']));
echo '&timestampTS_03='.(microtime(true) - $startT);

transactions 表目前有大约 200 万个条目。

CREATE TABLE IF NOT EXISTS `transactions` (
  `id` int(11) NOT NULL,
  `data` varchar(1000) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

【问题讨论】:

  • MyISAM 不是最好的存储选项,至少测试一下 InnoDB
  • concurrent_insert的值是多少?
  • @Dagon 这个表通常是 InnoDB,因为我们有更多的插入和很少的 SELECT 数据。但问题是因为它是 InnoDB,所以我们切换到 MyISAM 看看它是否表现得更好。当表是 InnoDB 时,我们没有监控每个查询。一旦我们发现问题,你认为它会像 InnoDB 那样表现得更好吗?因为很明显不是来自DB存储类型。
  • @Buddy 我可以使用 phpMyAdmin 或执行任何查询来找到它吗?或者我怎样才能得到“concurrent_insert”的值?
  • 另外,5.1 的日期是 2010 年而不是 2013 年。仅仅因为您的主机懒得升级他们的标准版本并不意味着他们做对了。我们在 rackspace 托管服务器上遇到了这种情况,当我问为什么它不是 5.5/5.6 时,他们似乎很惊讶。只是安全性增强使它变得轻而易举,更不用说提高性能了,尤其是 InnoDB

标签: php mysql


【解决方案1】:

InnoDB。 (因为下面有些东西需要它。)

批量插入。 Either by INSERT ... VALUES (1,2,3), (4,5,6), ...LOAD DATA。 (一次插入 100 行时性能提升 10 倍。)如果您无法“批处理”,请参阅下面的“暂存表”建议。

innodb_flush_log_at_trx_commit=2(不是默认值 1)(这可能是您的测试未能显示良好性能的原因。)

innodb_buffer_pool_size = 可用 RAM 的 70%。 (在您的 8GB 机器中大约有 5000M)。

从 5.1 升级。 (但这并不能单独解决问题。)

如果可能,减少transactions 上的索引数。

要获得真正的高摄取率,请按 High Speed Ingestion 中讨论的两个“临时表”进行 ping-pong。

【讨论】:

  • a)我们数据库中的每个表都只有主键,这意味着 1 个索引。 b)缓冲池是不是太多了... 70%的RAM? RIight 现在是 15% 左右。 c) 对于每个用户请求,都会进行一次 INSERT 查询。那么,您是否建议将来自不同连接的多个 INSERT 查询组合在一起,并在它们达到 100 行时一次性运行它们?
  • ids 是你编的吗?看起来他们不是AUTO_INCREMENT。如果每个连接都进行一次插入,那么将它们批处理是没有意义的——除非您需要每秒插入数百行。然后“批量”它们会变得很棘手。
  • 由于“表锁定”,MyISAM 可能需要 14 秒。 InnoDB 14 秒的简单 INSERT 意味着表发生了 big 事件——例如 ALTER TABLE 或不使用索引的 UPDATE。使用SHOW PROCESSLIST 来查看在缓慢的 INSERT 发生时正在运行的内容。
  • 自动提交使用什么值?你会BEGIN...COMMIT吗?
  • 检查是否启用了密钥打包可能也是值得的。密钥打包基本上是字符串截断以加快读取速度,但会减慢写入速度。
【解决方案2】:

您的表可能因另一个进程而被锁定。这可能是硬件问题(硬盘驱动器速度慢或使用寿命结束)、软件问题或推测性问题(共享系统中的服务器速度慢)。

您可以使用show processlist 查看锁定插入的内容

【讨论】:

  • -1 表示不推荐使用的功能:“从 MySQL 5.6.6 开始,不推荐使用 INSERT DELAYED,并将在未来的版本中删除。”
  • 感谢您注意到这一点,我删除了这一行,因为它不是我回答的第一个要点
  • 感谢您的提示。我认为这是问题所在。运行show processlist 查询时,我看到了几个进程的列表。你认为切换到 InnoDB 会解决这个问题吗?
  • 让我们看看PROCESSLIST
  • 您必须阅读您的进程列表才能找到正在执行并锁定其他进程的进程。很难说切换到 innodb 会改变任何东西而不知道它是哪个进程。但是如果它有效,你可以尝试一下。但假设它可能是硬件,那么您不会看到错误这一事实并不意味着它不存在。
【解决方案3】:

在任何数据库中(无论引擎如何)the highest cost is always in writing data,因为您添加了强制磁盘操作的开销(如果有足够的 RAM,MySQL 服务器可以很好地缓存表和查询以避免SELECT 的高 I/O) . MyISAM(带表锁定)可能对 InnoDB(带行锁定)没有帮助,但您不一定要切换存储引擎。

多个插入的一个主要技巧是使用prepared statement。您设置一次查询,然后更改参数并每行执行一次。如MySQL Manual for speed(强调我的)中所述

插入一行所需的时间由以下因素决定,其中数字表示大致比例:
连接:(3)
向服务器发送查询:(2)
解析查询:(2)
插入行:(1 × 行大小)
插入索引:(1 × 索引数)
结束:(1)

因为准备好的语句只发送和解析一次(上面加粗),它节省了相当多的开销,并保护了您的数据插入。

另一个选项是启用concurrent inserts。如果您不从该表中删除数据,这只是一个选项。

最后一个对您来说可能并不可行,但如果这是您业务的主要痛点,则应该考虑一下。现代云计算大大降低了更高 I/O 选项(RAID、SSD 等)的成本。您可能希望切换到具有高 I/O 选项的云服务(AWS、Azure 等)。您可以在数据库中投入任意数量的 RAM,但如果您的存储速度很慢,这只会拖累数据库的其余部分。

【讨论】:

  • 感谢您的解释。我们将增加并发插入的数量,我们将增加缓冲区大小,并将使用 MyISAM 与 InnoDB 进行一些测试,看看哪个提供了最佳性能。
【解决方案4】:

首先检查transactions 表是否被引用为外键的持有者。

然后运行show triggers 并检查是否有任何触发器设置为在transactions 或任何引用表发生变化时运行。

然后调整找到的所有触发器。

如果这没有帮助,请返回到您添加到代码中的跟踪,并添加以下内容:就在运行查询之前,检查哪些查询当时已经在运行,并将其记录下来。您可能会发现一些正在运行的慢查询正在锁定您的表。

【讨论】:

  • 目前我们的任何表上都没有触发器。我如何检查当时哪些查询已经在运行?可能是 MyISAM 锁定了较慢连接的表,并且其他一些查询变得更慢?我收到了很多关于切换到 InnoDB 的建议。
【解决方案5】:

您应该使用InnoDB 引擎而不是MyISAM 您可以通过此站点配置您的 mysql 配置:
www.percona.com

注意:innodb-buffer-pool 在您的配置中非常重要

【讨论】:

  • 是的,我同意。我已经改成 InnoDB,但性能没有变化。
  • 因为InnoDB需要配置,你的my.cnf数据是什么?请贴出来,你可以在/etc/my.cnf找到
  • 在忙于 percona 的同时,安装 cacti 和用于 cacti 的 percona-mysql 插件。这将使您深入了解您的 mysql 数据库以及您可以调整的内容。
【解决方案6】:

在大数据上使用mysqli,它具有多个插入语句功能。

在专用服务器中更可取。

查看链接 - http://www.w3schools.com/php/php_mysql_insert_multiple.asp

问候

【讨论】:

  • 因此,我不是为 2 个 INSERT 查询连接到 mysql 服务器 2 次,而是只连接一次,然后将它们都插入,与 2 相比,这样可能会将内存和响应时间减少一半请求单独发送。
  • 是的,大多数网络托管服务提供商正在切换到 mysqli,因为它的性能和功能。而且您不必像其他人所说的那样更改您的数据库设置。你必须使用它。
  • 如果需要那么你必须使用多个插入,你可以使用while循环来创建多个插入查询。然后执行它。
猜你喜欢
  • 2017-07-29
  • 2019-03-16
  • 2018-03-06
  • 2019-02-09
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 2023-04-10
  • 2011-03-10
相关资源
最近更新 更多