MySQL在MEMORY表

时间:2015-05-27 17:51:28

标签: mysql sql-insert database-performance

我正在尝试将大型(68K行)插入优化到临时表中。我将表创建为MEMORY引擎表,根本没有索引或外键。当我的ETL进程开始插入时,插入执行但非常缓慢;满负荷需要一个多小时。

这是show table create:

中的表定义
CREATE TABLE `pub_tair_germplasm` (
  `germplasm_id` int(12) DEFAULT NULL,
  `name` varchar(100) DEFAULT NULL,
  `original_name` varchar(100) DEFAULT NULL,
  `sp_growth_conditions` varchar(2048) DEFAULT NULL,
  `description` varchar(2048) DEFAULT NULL,
  `description_uc` varchar(2048) DEFAULT NULL,
  `is_mutant` varchar(1) DEFAULT NULL,
  `is_aneuploid` varchar(1) DEFAULT NULL,
  `ploidy` varchar(4) DEFAULT NULL,
  `species_variant_id` int(12) DEFAULT NULL,
  `taxon_id` int(12) DEFAULT NULL,
  `aneuploid_chromosome` int(10) DEFAULT NULL,
  `date_entered` date DEFAULT NULL,
  `date_last_modified` date DEFAULT NULL,
  `tair_object_id` bigint(19) DEFAULT NULL,
  `is_obsolete` varchar(1) DEFAULT NULL,
  `tair_object_type_id` int(12) DEFAULT NULL,
  `germplasm_type` varchar(20) DEFAULT NULL
) ENGINE=MEMORY DEFAULT CHARSET=latin1

这是插入内容:

INSERT INTO pub_tair_germplasm(
   germplasm_id,
   name,
   original_name,
   sp_growth_conditions,
   description,
   description_uc,
   is_mutant,
   is_aneuploid,
   ploidy,
   species_variant_id,
   taxon_id,
   aneuploid_chromosome,
   date_entered,
   date_last_modified,
   tair_object_id,
   is_obsolete,
   tair_object_type_id,
   germplasm_type)
VALUES (
   $germplasm_id,
   $name,
   $original_name,
   $sp_growth_conditions,
   $description,
   $description_uc,
   CASE $is_mutant WHEN 'F' THEN 'n' WHEN 'T' THEN 'y' ELSE 'y' END,
   CASE $is_aneuploid WHEN 'F' THEN 'n' WHEN 'T' THEN 'y' ELSE 'y' END,
   $ploidy,
   $species_variant_id, 
   $taxon_id,
   $aneuploid_chromosome,
   $date_entered,
   $date_last_modified,
   $tair_object_id,
   $is_obsolete,
   $tair_object_type_id,
   $type)

这是通过Clover / ETL完成的,它通常使用批处理大小为5000的JDBC批处理非常快速地插入。值变量是CloverETL变量引用。 Oracle上的类似插入需要几秒钟才能进入常规表。这一切都在一个事务中完成,在插入所有行之前都没有提交(应用程序要求)。

当插件运行时,top显示两个CPU都使用了0.3%。

编辑:

对于下一次测试运行,我将最大堆表大小增加到1GB,足以容纳整个表:

mysql> select @@max_heap_table_size;
+-----------------------+
| @@max_heap_table_size |
+-----------------------+
|             999999488 |
+-----------------------+

开始时的流程清单:

mysql> SHOW FULL PROCESSLIST;
+----+------+-----------+-------+---------+------+-------+-----------------------+
| Id | User | Host      | db    | Command | Time | State | Info                  |
+----+------+-----------+-------+---------+------+-------+-----------------------+
|  3 | root | localhost | mysql | Query   |    0 | NULL  | SHOW FULL PROCESSLIST |
+----+------+-----------+-------+---------+------+-------+-----------------------+
1 row in set (0.00 sec)

运行期间的流程清单:

mysql> SHOW FULL PROCESSLIST;
+----+---------+--------------------------------------------+-------+---------+------+-------+-----------------------+
| Id | User    | Host                                       | db    | Command | Time | State | Info                  |
+----+---------+--------------------------------------------+-------+---------+------+-------+-----------------------+
|  4 | pubuser | c-67-188-135-136.hsd1.ca.comcast.net:55928 | pub   | Sleep   |    0 |       | NULL                  |
|  5 | root    | localhost                                  | mysql | Query   |    0 | NULL  | SHOW FULL PROCESSLIST |
+----+---------+--------------------------------------------+-------+---------+------+-------+-----------------------+
2 rows in set (0.00 sec)

我启用了常规日志文件;它显示了发布的CloverETL环境设置命令,然后进入一系列插入:

150528 20:22:54     4 Connect   pubuser@c-67-188-135-136.hsd1.ca.comcast.net on pub
                    4 Query     /* mysql-connector-java-5.1.20 ( Revision: tonci.grgin@oracle.com-20111003110438-qfydx066wsbydkbw ) */SHOW VARIABLES WHERE Variable_name ='langua
ge' OR Variable_name = 'net_write_timeout' OR Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR Variable_name = 'character_set_client' OR Variable_name 
= 'character_set_connection' OR Variable_name = 'character_set' OR Variable_name = 'character_set_server' OR Variable_name = 'tx_isolation' OR Variable_name = 'transaction_isola
tion' OR Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR Variable_name = 'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name = 'lower_cas
e_table_names' OR Variable_name = 'max_allowed_packet' OR Variable_name = 'net_buffer_length' OR Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type' OR Variable_nam
e = 'query_cache_size' OR Variable_name = 'init_connect'
                    4 Query     /* mysql-connector-java-5.1.20 ( Revision: tonci.grgin@oracle.com-20111003110438-qfydx066wsbydkbw ) */SELECT @@session.auto_increment_increment
                    4 Query     SHOW COLLATION
150528 20:22:55     4 Query     SET NAMES latin1
                    4 Query     SET character_set_results = NULL
                    4 Query     SET autocommit=1
                    4 Query     SET sql_mode='STRICT_TRANS_TABLES'
                    4 Query     SET autocommit=0
                    4 Query     SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
150528 20:23:08     4 Query     INSERT INTO pub_tair_germplasm(
   germplasm_id,
   name,
   original_name,
   sp_growth_conditions,
   description,
   description_uc,
   is_mutant,
   is_aneuploid,
   ploidy,
   species_variant_id,
   taxon_id,
   aneuploid_chromosome,
   date_entered,
   date_last_modified,
   tair_object_id,
   is_obsolete,
   tair_object_type_id,
   germplasm_type)
VALUES (
   500689369,
   'CS2000002',
   'CS2000002',
   'none',
   'Sequence-indexed T-DNA insertion line; from the GABI-Kat project (German Plant Genomics Program - Koelner Arabidopsis T-DNA lines); generated using flanking sequence tags (F
STs) in the Columbia (Col-0) background; genomic DNA was isolated from T1 plants; plant sequences adjacent to T-DNA borders were amplified by adapter-ligation PCR; automated pur
ification and sequencing of PCR product were conducted followed by computational trimming of the resulting sequence files; for details, see the GABI-Kat web site: http://www.gab
i-kat.de; this is a T4 generation single-plant line potentially homozygous for the insertion. May be segregating for phenotypes that are not linked to the insertion; may have ad
ditional insertions potentially segregating.',
   'SEQUENCE-INDEXED T-DNA INSERTION LINE; FROM THE GABI-KAT PROJECT (GERMAN PLANT GENOMICS PROGRAM - KOELNER ARABIDOPSIS T-DNA LINES); GENERATED USING FLANKING SEQUENCE TAGS (F
STS) IN THE COLUMBIA (COL-0) BACKGROUND; GENOMIC DNA WAS ISOLATED FROM T1 PLANTS; PLANT SEQUENCES ADJACENT TO T-DNA BORDERS WERE AMPLIFIED BY ADAPTER-LIGATION PCR; AUTOMATED PUR
IFICATION AND SEQUENCING OF PCR PRODUCT WERE CONDUCTED FOLLOWED BY COMPUTATIONAL TRIMMING OF THE RESULTING SEQUENCE FILES; FOR DETAILS, SEE THE GABI-KAT WEB SITE: HTTP://WWW.GAB
I-KAT.DE; THIS IS A T4 GENERATION SINGLE-PLANT LINE POTENTIALLY HOMOZYGOUS FOR THE INSERTION. MAY BE SEGREGATING FOR PHENOTYPES THAT ARE NOT LINKED TO THE INSERTION; MAY HAVE AD
DITIONAL INSERTIONS POTENTIALLY SEGREGATING.',
   CASE null WHEN 'F' THEN 'n' WHEN 'T' THEN 'y' ELSE 'y' END,
   CASE 'F' WHEN 'F' THEN 'n' WHEN 'T' THEN 'y' ELSE 'y' END,
   '2',
   null, 
   1,
   null,
   '2015-01-06 10:49:21',
   '2015-01-06 10:40:55',
   6530679980,
   'F',
   200016,
   'individual_line')

问题仍然没有改变。

3 个答案:

答案 0 :(得分:1)

好吧,我不知道具体是什么问题,但是将制表符分隔的数据版本上传到mysql服务器并执行此操作:

func f(listOfUrls []string){
  var wg sync.WaitGroup
  wg.Add(len(listOfUrl))
  for _, myurl := range(listOfUrls){
    myurl := myurl
    go func(){
           body := getUrlBody(myurl)
           fmt.Println(len(body))
           wg.Done()
       }()    
  } 
  wg.Wait()
}
无论什么问题,

显然都​​是答案。在Clover / ETL中,必须在JDBC批处理中执行某些操作,这会大大减慢插入速度。如果我有机会,我会调查一下,但是现在LOAD给了我我需要的东西。

答案 1 :(得分:0)

我怀疑您正试图超过使用MEMORY存储引擎的表所允许的最大大小。但我不明白为什么MySQL没有返回错误,或者Clover / ETL没有返回错误或超时。

我建议您从

收集输出
SHOW FULL PROCESSLIST

查看当前会话的状态。也许INSERT声明是“挂”?

您也可以暂时启用常规日志

SET GLOBAL general_log = 1

然后尝试加载。该日志文件可以非常快地增长,因此您希望确保将其设置为0以禁用它。

正如我在评论中指出的那样,我正在计算表格的大小超过415MB。这是基于使用MEMORY引擎(固定长度行),行大小为6407字节(假设字符列为单字节字符集),不包括空指示符的行开销。

摘自MySQL参考手册, 15.3 MEMORY存储引擎

部分
  

MEMORY表的最大大小受 max_heap_table_size 系统变量的限制,该变量的默认值为16MB。要对MEMORY表强制执行不同的大小限制,请更改此变量的值。 CREATE TABLE 或后续 ALTER TABLE TRUNCATE TABLE 的有效值是值用于表的生命。服务器重新启动还会将现有MEMORY表的最大大小设置为全局 max_heap_table_size 值。您可以设置各个表的大小,如本节后面所述。

参考:https://dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html

另外,我们注意到MEMORY存储引擎不支持事务。

如果您要求在加载数据时没有其他会话看到数据,您可以考虑使用InnoDB或MyISAM,并加载到不同的表名,然后尽快重命名表当负载完成时。

或者,使用InnoDB存储引擎和hughjass事务。将所有INSERT操作作为单个事务的一部分进行。 (但是,我不喜欢这种方法;我害怕产生大量的回滚。)

或者,使用MyISAM存储引擎。在表上取一个LOCK,执行所有INSERT操作,然后释放锁。 (但是,试图引用该表的任何其他语句都会“挂起”等待锁被释放。)

答案 2 :(得分:0)

从广义上讲,5000个陈述的批量大小被认为太大了。实际的最佳JDBC批处理大小取决于多个条件。但是,50到100之间的数字应该没问题。您可以尝试更多的课程,并尝试为您找到合适的号码。我肯定会对数字进行一些调整,并检查性能如何随不同的数字而变化。

关于内存要求(这也是使用批量大小时发挥作用的因素之一),似乎基于CREATE语句,行的最大大小为6418字节。因此,如果您有大约68k的这些行(按此行的最大大小计算),此任务所需的最大内存大约为450GB。但是,这甚至不是您定义的max_heap_table_size的一半。所以如果表是空的,应该没有问题。此外,如果达到MEMORY表的限制,CloverETL图将在适当的SQLException(java.sql.SQLException: The table <YOUR_MEMORY_TABLE>' is full)上失败。但事实并非如此。

我想到的另一个选项(并且与前面提到的注释有关)是你实际上没有足够的可用内存来将数据存储在内存中,因此数据在磁盘上交换。这可能会澄清性能下降。但是,如果你用尽所有可用的虚拟内存(RAM和交换),你很可能会遇到另一个有不同症状的问题 - 所以不会那样。

也许,如果上面没有任何帮助,你可以与我们分享来自CloverETL图执行的日志(如果可能的话,在DEBUG日志级别执行),以便我们可以看到是否有任何可疑的东西。除此之外,商业版的CloverETL还附带MySQLDataWriter,它使用MySQL本机客户端,可能还可能解决与JDBC相关的问题。我会从找到合适的批量大小开始。