繁体   English   中英

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

[英]Why does SQLyog returns MySQL query results 10x faster than my Delphi program?

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毫秒即可完成查询,甚至无需查看结果。

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

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

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

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

也知道ODBC更慢,因为它为本机访问添加了更多层,所以尝试使用DevArt中的MyDac ,它使用直接访问mysql(即使没有mysql客户端库)。

而且最重要的是,永远不要试图一次向用户显示80,000条记录。

BTW,使用Delphi构建的sun官方MySql GUI工具 ;-)

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

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

正如其他人所说,这可能是因为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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM