2012-04-02 125 views
1

我需要插入一个MySQL的InnoDB表从远程客户端的数据行的许多数以万计。客户端(Excel的VBA超过经由ADO MySQL的ODBC连接器)可以生成CSV和执行LOAD DATA LOCAL INFILE,或者可以准备一个巨大INSERT INTO ... VALUES (...), (...), ...语句和执行。前者需要一些rather ugly hacks来克服Excel's inability to output Unicode CSV natively(它只在系统区域设置的默认代码页中写入CSV,在许多情况下它是单字节字符集,因此非常有限);但MySQL documentation表明它可能比后一种方法快20倍(为什么?),它也“感觉”,好像由于SQL命令极长而可能不太稳定。速度INSERT VS LOAD DATA LOCAL INFILE的

我还没有能够标杆两种方法,但我会听到的可能性能/稳定性问题的想法很感兴趣。

回答

1

我想也许一个混合解决方案将工作做好在这里...是... ...

首先创建性能

PREPARE stmt1 FROM 'INSERT INTO table (column1, column2, ...) VALUES (?, ?, ...)'; 

一份声明中观察到的?标记是实际的语法 - 无论您打算最终如何使用从CSV文件解析的值,都可以使用问号。

编写一个打开.CSV文件并进入循环的过程或函数,该循环一次读取一行内容(一次一个记录),将解析列的值存储在单独的变量中。

然后,在这个循环中,只是读出记录到本地变量后,您可以设置在准备好的声明中的值在局部变量的当前记录,如...

SET @a = 3; 
SET @b = 4; 

应该有SET语句的数量与CSV文件中的列数相同。如果没有,你错过了一些东西。顺序是非常重要的,因为您必须根据?的位置设置值。在准备好的声明中标记。这意味着您将必须确保SET语句与INSERT语句中的列匹配。

所有参数的设置对于准备语句之后,然后执行它。

EXECUTE stmt1 USING @a, @b; 

然后这是循环的结束。刚退出循环(到达CSV文件结束后),您必须释放准备的语句,如...

DEALLOCATE PREPARE stmt1; 

重要的事情要记住的是...

制作确保在进入循环读取记录之前准备好INSERT语句,并确保在退出循环后DEALLOCATE语句。

预处理语句允许数据库预编译和优化语句一次,然后多次不断变化的参数值执行。这应该会提高性能。

我不确定MySQL,但有些数据库还允许您在准备好的语句在网络中实际执行之前指定要缓存的行数 - 如果MySQL有这种可能性,这样做可以让您告诉数据库尽管您正在从CSV中读取的每一行调用execute语句,但数据库应该将语句批量添加到指定的行数,然后才能通过网络执行。通过这种方式,性能会大大提高,因为数据库可能会批量增加5或10个INSERTS,并在网络上只使用一次往返而不是每行执行一次。

希望这有助于并有意义。祝你好运!

Rodney

+0

谢谢罗德尼 - 有趣的方法。事实证明,其他一些(令人沮丧的)问题阻止我们每个数据库会话发送多个命令;所以我们必须建立TCP,对MySQL进行身份验证,发送单个查询,拆除会话并重新开始。这不仅会增加额外开销,导致单独发送10K个记录,当然,准备好的语句也不会在各个会话中持续存在。因此,我采用丑陋的黑客方式为'LOAD DATA'输出UTF-8 CSV。 – eggyal 2012-04-04 00:18:11