INSERT INTO SELECT在集群上需要很长时间

时间:2017-07-27 10:20:52

标签: mysql query-performance mysql-cluster percona-xtradb-cluster

我的mysql群集:INSERT INTO `sometable` (SELECT ...);

我有一个复杂的SQL查询,它使用以下语法将大约36k行插入到表中:

CREATE TABLE `sometable` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) unsigned DEFAULT NULL,
  `a` varchar(255) DEFAULT NULL,
  `b` smallint(6) unsigned DEFAULT NULL,
  `c` smallint(6) unsigned DEFAULT NULL,
  `d` smallint(6) unsigned DEFAULT NULL,
  `e` smallint(6) unsigned DEFAULT NULL,
  `f` varchar(255) DEFAULT '',
  `country_id` int(10) unsigned DEFAULT NULL,
  `city_id` int(10) unsigned DEFAULT NULL,
  `g` smallint(6) unsigned DEFAULT NULL,
  `h` smallint(6) unsigned DEFAULT NULL,
  `i` smallint(6) unsigned DEFAULT NULL,
  `j` smallint(6) unsigned DEFAULT NULL,
  `k` smallint(6) unsigned DEFAULT NULL,
  `l` varchar(3) DEFAULT NULL,
  `m` varchar(3) DEFAULT NULL,
  `n` text,
  `o` varchar(255) DEFAULT NULL,
  `p` varchar(32) DEFAULT NULL,
  `q` varchar(32) DEFAULT NULL,
  `r` varchar(32) DEFAULT NULL,
  `s` time DEFAULT NULL,
  `t` time DEFAULT NULL,
  `u` text,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `country_id` (`country_id`),
  KEY `city_id` (`city_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

选择有点复杂但不慢(0.0023s)但插入需要大约40-50s。我在插入行时没有使用该表。

我的问题是:

  • 我能以某种方式加快速度吗?
  • 慢速插入导致其他表上的锁定问题(因为选择)
  • 这个工作流程是好还是坏的做法?还有更好的吗?

由于

更新

表架构:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

UPDATE2:

当我尝试运行查询时,在某些情况下会出现错误:

mytable

我的解决方案:

如果有兴趣的人,这是我的最终解决方案: gist

主要问题是,当我填充mytable时,其他查询被卡住,群集出现了严重的性能问题。在这个解决方案中,我创建了一个临时表,并在“脏读”模式下用数据填充它,然后我将这些数据以块的形式复制到await _signInManager.RefreshSignInAsync(user);,这样它需要更多的时间,但没有性能问题而且没有卡住查询。

2 个答案:

答案 0 :(得分:1)

一个value操作,每隔64纳秒返回一行描述的行,速度非常快。这就是2.3毫秒内36千里的成功率。您的SELECT查询时间似乎不会将结果集传输到MySQL客户端。无论如何,使用该性能作为INSERT操作的比较会使您的期望值过高。

您可以在开始操作之前尝试发出此命令。它将允许您的SELECT操作继续使用SELECT的源表上的应用程序流量进行较少的争用。见https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html

SELECT

您可以尝试一个包含临时表的两步过程。这样做的好处是不必在SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 操作的同时更新some_table中的所有索引。该操作将如下所示。

SELECT

您应该了解InnoDB将您的一批插入作为单个事务发布到您的表中。如果你能够以一次处理大约500行而不是36K的方式执行此操作,那么您将拥有更多的事务,但它们会更小。这通常是获得更高吞吐量的一种方式。

答案 1 :(得分:1)

如果一切都失败了,这可能是一个可行的解决方案。首先,请参阅http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks

  1. 将更正加载到临时表(或非复制的MyISAM表)。
  2. 循环访问临时表(使用与该链接类似的代码)。一次挑100行。
  3. 单独的交易中执行100行中的INSERT ... SELECT ...
  4. 此技术可能(或可能不会)花费超过40-50秒,但至少不会超时或死锁。

    通常,避免运行任何持续时间超过几秒的事务。这个链接在如何“分块”冗长(和重复)操作以避免长事务方面有点泛泛。