0

我的MySQL集群:Ver 5.6.30-76.3-56 for debian-linux-gnu on x86_64 (Percona XtraDB Cluster (GPL), Release rel76.3, Revision aa929cb, WSREP version 25.16, wsrep_25.16)INSERT INTO SELECT时间长集群

我有一个复杂的SQL查询其插入约36K行入表的语法如下:

INSERT INTO `sometable` (SELECT ...); 

的选择是有点复杂但不慢(0.0023s),但插入大约需要40-50s。当我插入行时,表格未被使用。

我的问题是:

  • 我能否加快点不知何故?
  • 慢插入导致其他表上的锁定问题(因为选择)
  • 此工作流程是好还是坏的做法?有没有更好的?

感谢

UPDATE:

表架构:

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; 

UPDATE2:

当我尝试运行查询,我得到一个错误有些情况下:

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

我的解决方案:

这是我最后的解决办法,如果有人感兴趣: gist

的主要问题是,虽然我填写mytable其他查询卡和集群有严重的性能问题。在这个解决方案中,我创建了一个临时表并在“脏读”模式下填充数据,然后我将这些数据以块的形式复制到mytable,因此需要多一点时间,但没有性能问题,也没有卡住查询。

+1

头脑与我们分享您的表的'CREATE语句TABLE'? (仅包含重要的东西,比如键,索引列,索引等) –

+1

请仔细阅读本http://meta.stackoverflow.com/a/271056/特别是对查询性能的一部分。那么请[编辑]你的问题。 –

+0

你确定你的'SELECT'操作真的很快吗?阅读此:http://meta.stackoverflow.com/a/271056/ –

回答

1

A SELECT返回您描述的每行64纳秒的行长度非常快。这就是2.3毫秒内产生的36千瓦。看起来您的SELECT查询时间可能不会将结果集传输到MySQL客户端。无论如何,将该性能与INSERT操作进行比较,可以让您的期望值过高。

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

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

你可以尝试两个步骤的过程,涉及到一个临时表。这将具有不需要在操作的同时更新some_table中的所有索引的优点。该操作看起来像这样。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
CREATE TEMPORARY TABLE insert_batch AS SELECT ... ; 
INSERT INTO some_table SELECT * FROM insert_batch; 
DROP TEMPORARY TABLE insert_batch; 

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

+0

谢谢,这真的帮了我很多。基于此我解决了这个问题。它不是那么快,但运行该过程时没有性能问题。 – MrRP

+0

不客气。如果你有时间,你可以发表评论,说明你做了什么以及它的性能有多大改进? –

+0

我用我的解决方案更新了这个问题。如果您对此有任何评论,我将非常感激。 – MrRP

1

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

  1. 装入修正到一个临时表(或非复制的MyISAM表)。
  2. 遍历临时表(使用类似于链路代码)。每次挑选100行。
  3. 不要在单独交易INSERT ... SELECT ... 100的行。

这种技术可能(或可能不)花费超过40-50s的时间,但至少不太可能发生超时或死锁。

一般来说,避免运行持续时间超过几秒钟,不再有任何交易。对于如何“分块”冗长(重复)操作以避免长时间事务,此链接有点泛泛。

+0

谢谢,我终于使用了块想法。 – MrRP