【问题标题】:Extremely slow insert from Delphi to Remote MySQL Database从 Delphi 到远程 MySQL 数据库的插入速度极慢
【发布时间】:2010-04-30 11:16:15
【问题描述】:

从 Delphi 2010 到远程 MySQL 5.09 服务器的插入速度极慢,存在一个严重的问题。

到目前为止,我已经尝试过:

  • 使用 MySQL ODBC 驱动程序的 ADO
  • Zeoslib v7 Alpha
  • MyDAC

我在 ADO 中使用了批处理和直接插入(使用表访问),在 Zeos 中我使用了带有查询的 SQL 插入,然后使用了直接表模式,还使用了应用更新和提交缓存更新表模式。使用 MyDAC,我使用表访问模式,然后直接 SQL 插入,然后批量 SQL 插入

我尝试过的所有技术,我都打开和关闭了压缩,没有明显的区别。

到目前为止,我已经看到了几乎相同的每秒 7.5 条记录!!!

现在,我从这一点开始假设远程服务器很慢,但 MySQL Workbench 速度非常快,并且迁移工具包非常快速地管理了初始迁移(老实说,我不记得有多快 -哪种表示它很快)

编辑 1

将 sql 写入文件,通过 ftp 将文件上传到服务器,然后将其直接导入远程服务器,这对我来说更快——我想知道他们是否可能会限制传入的 MySQL 流量,但这并没有解释为什么 MySQL Workbench 这么快!

编辑 2

在最基本的层面上,代码是:

while not qMSSQL.EOF do
begin
  qMySQL.SQL.Clear;
  qMySQL.SQL.Add('INSERT INTO tablename (fieldname1) VALUES (:fieldname1)');
  qMySQL.ParamByName('fieldname1').asString:=qMSSQL.FieldByName('fieldname1').asString;
  qMySQL.ExecSQL;
  qMSSQL.Next;
end;

然后我尝试了

qMySQL.CachedUpdates:=true;
i:=0;
while not qMSSQL.EOF do
begin
  qMySQL.SQL.Clear;
  qMySQL.SQL.Add('INSERT INTO tablename (fieldname1) VALUES (:fieldname1)');
  qMySQL.ParamByName('fieldname1').asString:=qMSSQL.FieldByName('fieldname1').asString;
  qMySQL.ExecSQL;
  inc(i);
  if i>100 then
  begin
    qMySQL.ApplyUpdates;
    i:=0;
  end;
  qMSSQL.Next;
end;
qMySQL.ApplyUpdates;

现在,在这段带有CachedUpdates:=False(显然从未真正写回数据库)的代码中,速度快得惊人!!

老实说,我认为这是一种联系 - 我感觉这是一种联系......只是等待他们回复我!

感谢您的帮助!

【问题讨论】:

  • 如果您显示您的代码,这将非常有助于检测您的瓶颈
  • 如果使用本地服务器,插入速度有多快?可能是与传输相关的问题(连接速度慢)。
  • 您的代码不正确。将 SQL 代码设置在循环外部,然后调用 Prepare。在循环内部只需分配参数并执行,否则您将失去参数的优势。在循环外显式启动事务,并在最后提交。 CachedUpdates 设置为 False 意味着数据直接进入数据库并且不在本地缓存。不要使用 CachedUpdates,它们不是为了速度。
  • @idsandon - 这只是测试代码,我实际上已经尝试使用不同的技术和组件进行多次迭代,但完全没有运气。

标签: mysql delphi


【解决方案1】:

您可以尝试AnyDAC 和它的Array DML 功能。它可能会加速标准 SQL INSERT 几次。

【讨论】:

  • 感谢 Dmitry,我尝试了一个演示,Array DML 功能看起来非常有趣 - 但可惜速度相似。
  • 我们尝试了使用 MySQL 的数组 dml - 这真的很快。您的系统上似乎有问题。
【解决方案2】:

很抱歉,这个回复是在您提出问题很久之后才出现的。

我遇到了类似的问题。 BDS2006 通过网络上的 ODBC 到 MySQL - 运行时间为 25 分钟 - 每秒大约 25 次插入。我正在使用 TDatabase 连接并将 TTable Tquery 附加到它。准备好 SQL 语句。

主要改进是当我开始在循环中开始事务时。一个简单的例子,会员有会员期。在插入Membership 和Members 之前启动事务,之后提交。会员数量为 01585,交易前处理所有会员记录需要 279.90 秒,但处理后需要 6.71 秒。

几乎令人难以置信,并且仍在努力修复其他慢位的代码。

也许马克你已经解决了你的问题,但它可能会帮助别人。

【讨论】:

  • 做了一些进一步的改变。提交是昂贵的,因此获得良好性能的关键是选择一个提交频率,以平衡提交的费用与持有事务太长时间的开销。
  • 经过进一步调整后,我设法使用事务将运行时间从 19 分钟减少到 51 秒。
  • +1 太好了,谢谢大卫!我现在实际上不记得我是否尝试过交易,当您说通过网络时,您是指通过本地网络还是互联网?
  • 马克,我最初对同一台服务器 (localhost) 上的 MySQL 进行了代码更改,今晚在我的本地网络上运行代码(从一台机器到 MySQL 服务器)这次花了 73 秒。抱歉没有在真正的互联网上运行它 - 怀疑网络延迟可能会更多。 HTH
【解决方案3】:

您是否使用查询参数?插入的最快方法应该是使用普通查询和参数(即 INSERT INTO table (field) VALUES (:field) ),准备查询,然后分配参数并在单个事务中根据需要执行多次 - 最后提交(不要使用任何类型的自动提交)

这在大多数数据库中避免了每次执行查询时都进行硬解析,这需要时间。参数允许查询只解析一次,然后根据需要重新执行多次。

使用服务器设施检查正在发生的事情 - 许多提供了一种检查正在运行的语句正在做什么的方法。

【讨论】:

  • 我一开始使用查询参数和批量插入(如果可以的话,我总是先尝试使用 SQL)但平均速度是一样的 :(
  • 我不会使用 ADO 批量插入,它可能会减少往返次数,但它可以控制插入,就像缓存更新一样。恕我直言,最快的方法是让语句以尽可能少的开销直接进入数据库。无论如何,首先你必须找到真正的瓶颈所在。
  • 对 Idsandon 的正确回答,他提到检查服务器设施,在这种情况下可能会回答我的问题(db 工作台结果一定是假的)
【解决方案4】:

我不确定 ZeosLib,但是使用 ADO 和 ODBC 驱动程序,您不会获得插入记录的最快方法,这里有几个步骤可能会使您的插入速度更快:

  1. 使用 Mydac 进行直接访问,它们无需缓慢的 ODBC > ADO > OLEDB > MySqlLib 即可连接到 Mysql。

  2. 在插入之前先打开连接。

  3. 如果您有大量插入,例如 1000 或更多,请尝试使用事务并在 100 或更多记录后提交,具体取决于记录数。

即使使用 ZeosLib 或 ADO,第 3 点也可能使您的插入速度更快。

【讨论】:

  • 感谢您的回答,但是我已经尝试了 2 和 3(目前仍在安装 MyDAC)我希望批量插入会更快,但它仍然以相同的平均速度出现就像通过网络一次插入一条记录一样!?
【解决方案5】:

这里发生了两件不同的事情。首先,您的 Delphi 程序正在创建 Insert 语句并将它们发送到 DB 服务器,然后服务器正在处理它们。您需要检查两端以找到瓶颈。我不熟悉 MySql 工具,但我敢打赌,你可以很容易地找到一个 SQL 分析器。使用它来分析来自 Delphi 应用程序的插入,并将其与从 Workbench 工具运行的插入进行比较,看看是否有显着差异。

如果不是,那么减速是在您的应用中。尝试将它连接到 Sampling Profiler 或其他一些了解 Delphi 的分析工具,它会告诉你你在哪里花费了大量时间。一旦你知道了,那么你就可以着手解决这个问题,或者回到这里问一个更具体的问题。但在你知道问题出在哪里之前,你在这里得到的任何答案充其量只是有根据的猜测。

【讨论】:

  • 谢谢梅森,我很确定这是服务器速度而不是我的代码,我只是不是 100% 确定我是否正确使用了 mysql 库,和/或最佳实践是什么关于 Delphi,但它们似乎与我尝试过的相似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-13
  • 2015-07-22
  • 2017-04-15
  • 1970-01-01
  • 2014-08-10
相关资源
最近更新 更多