INSERT与LOAD DATA LOCAL INFILE的速度

时间:2012-04-02 22:56:36

标签: mysql database

我需要从远程客户端插入MySQL InnoDB表中的数万行数据。客户端(通过ADO的Excel VBA over 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命令,它也“感觉”好像可能不太稳定。

我还没有能够对这两种方法进行基准测试,但我很想听听有关可能的性能/稳定性问题的想法。

1 个答案:

答案 0 :(得分:1)

我想也许混合解决方案可以在这里运作良好......就像......

首先为性能创建一个准备好的声明

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

观察到了吗?标记是实际语法 - 无论您希望最终使用从CSV文件解析的值,都使用问号。

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

然后,在这个循环中,在将记录读入局部变量之后,将准备好的语句中的值设置为局部变量中的当前记录,如...

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

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

设置准备好的语句的所有参数后,执行它。

EXECUTE stmt1 USING @a, @b;

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

DEALLOCATE PREPARE stmt1;

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

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

Prepared语句允许数据库一次预编译和优化语句,然后使用更改的参数值多次执行。这应该会带来不错的性能提升。

我不确定MySQL,但是一些数据库还允许你在准备好的语句实际在网络上执行之前指定要缓存的行数 - 如果这可以用于MySQL,这样做可以让你告诉数据库虽然您在从CSV读取的每一行的语句上调用execute,但数据库应该将语句批处理到指定的行数,然后才能通过网络执行。这样,性能大大提高,因为数据库可以批量运行5或10个INSERTS,并且只使用网络上的一次往返而不是每行一次来执行它们。

希望这有帮助并且相关。祝你好运!

罗德尼