为什么SQLyog返回的MySQL查询结果比我的Delphi程序快10倍?

时间:2009-06-23 09:19:27

标签: mysql delphi optimization odbc

select rectype,jobid,jobrecid,template,assignedto,entereddt,enteredby,ref1,processed,processeddt,
processbydt,title,description,connectlanhandle,finished,updateddt,ref2,cancelled,
requireaccept,acceptrejectstate,acceptrejectbydt,alert1dt,alert2dt,alert3dt,despatchallowed,
flag,ref3,projectid,duration,skillset,postcode,prefschedulefrom,prefscheduleto,customdata1,
customdata2,customdata3,hasnotes,displayjobtype,createdby,createddt,colour
 from jobs
 where updateddt >= '1982-02-05 17:25:38'
 or (processed = 'N' and
     cancelled = 'N')
 order by jobid, jobrecid

此查询返回~80000结果。 SQLyog(MySQL gui)可以在~600ms内在可见网格中返回结果。我的Delphi程序使用ODBC(最新的MyODBC驱动程序)进行连接,只需要6000毫秒即可完成查询,甚至无需查看结果。

关于如何让我的程序更快的任何想法?

7 个答案:

答案 0 :(得分:6)

我的猜测是,SQLyog实际上并没有在600毫秒内显示所有80,000个结果 - 它可能仍在加载后者,而它显示的是第一个。 (特别是,即使没有涉及数据库,我见过的大多数GUI框架都无法快速填充80,000行。)

你可以尝试做同样的事情,假设你正在使用的API让你以流式方式获得结果(而不是在调用返回之前将所有内容都传输到内存中)。

答案 1 :(得分:5)

我在基本表(无联接)上尝试了这个,发现即使你单击“全部显示”复选框,SQLyog也不会立即将所有结果都带到网格上,通过移动滚动按钮来尝试自己最低的区域,你会发现sqlyog会减速一段时间,并带来更多的结果显示。

还知道ODBC速度较慢,因为它为本机访问添加了更多层,因此尝试使用直接访问mysql的MyDac from DevArt(即使没有mysql客户端库)。

并且正如大多数人所说,永远不要试图一次向用户显示80,000条记录。

顺便说一下,使用Delphi建立的sun官方MySql GUI tools; - )

答案 2 :(得分:2)

我想这是因为SQLyog使用本机MySQL C API(直接连接),而您使用的是ODBC连接器。 您是否尝试过Devart的MyDAC等第三方连接器?您可以从那里获得免费试用版并使用它来测试您的应用程序。

FWIW我现在使用MyDac多年了,我对(表现/奖品/支持)非常满意

答案 3 :(得分:2)

正如其他人所说,这可能是因为SQLyog没有加载所有记录,并且可能将其限制在200左右。

为了解决此性能问题,您可以使用偷偷摸摸的技巧。由于您基本上是在启动时将数据集的缓存加载到应用程序中,因此可以对此进行处理。加载仍需要6或8秒,但您的应用程序仍然可以启动并且UI可用。如果有人在加载之前做了一些需要缓存的东西,你可以简单地显示沙漏光标,或者说“需要一会儿......”的消息,直到缓存准备就绪。

在线程中进行数据访问时要注意的一件事是,您通常需要在线程中创建单独的数据库连接。像这样:

type
  TLoadCacheThread = class(TThread)
  private
    FConnection : TODBCConnection; // Or whatever, I don't use ODBC :-)
    FQuery : TODBCQuery;
    FMemData : TkbmMemTable; // This is what I use, YMMV
  protected
    procedure PopulateCachedDataset;
  public
    constructor Create; override;
    procedure Execute; override;
  end;

constructor Create;
begin
  inherited Create(True); // create suspended thread
  FConnection := TODBCConnection.Create(nil);
  // Set any properties for the connection here.
  FQuery := TODBCQuery.Create(nil);
  // Set any properties for the query here.
  FQuery.SQL.Text := 'select * from mytable';
  Resume;
end;

procedure Execute;
begin
  FQuery.Open;
  FMemTable.LoadFromDataset(FQuery);
  Synchronize(PopulateCachedDataset);
end;

// The idea here is that you're loading into a mem dataset, which can then
// quickly be copied to another memory dataset, rather than loading the
// cached data directly from FQuery, which is slow and why we're threading
// in the first place. This assumes you have some kind of globalsettings unit
// or class, and it has a cacheddataset variable or property.
procedure PopulateCachedDataset;
begin
  GlobalSettings.CachedDataset.LoadFromDataset(FMemTable);
end;

无论如何,这是基本的想法。还有其他方法更复杂但技术上更优越,比如使GlobalSettings.CachedDataset按需加载数据,因此第一次访问它时会很慢,但后续时间会更长,等等。但是,它将取决于你的需求。

HTH

答案 4 :(得分:1)

你可以在查询时使用LIMIT 0,1000,然后在用户到达远端时更改它 - 通过检查OnAfterScroll事件。

答案 5 :(得分:0)

在我看来,你应该对你的应用程序和/或数据库架构三思而后行 - 在处理80K记录时并不好。尝试缩小查询范围 - 如果你不能让你的生活变得更简单 - 没有人愿意花钱)

答案 6 :(得分:0)

SQLyog可能不会一次加载所有80000行,至少我使用的一些数据库工具在滚动时会“按需加载”。如果您需要一次性获取所有记录,请考虑使用线程执行查询并填充内部数组。