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

发布于 2024-07-25 04:02:44 字数 768 浏览 6 评论 0原文

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)可以在约 600 毫秒内以可见网格形式返回结果。 我的 Delphi 程序使用 ODBC(最新的 MyODBC 驱动程序)进行连接,仅执行查询就需要约 6000 毫秒,甚至没有开始查看结果。

关于如何使我的程序更快有什么想法吗?

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

This query returns ~80000 results. SQLyog (a MySQL gui) can return the results in a visible grid in ~600ms. My Delphi program, which connects using ODBC (latest MyODBC drivers), takes ~6000ms just to do the query, without even starting to look at the results.

Any ideas on what I can do to make my program faster?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

心作怪 2024-08-01 04:02:44

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

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

My guess is that SQLyog hasn't actually displayed all 80,000 results in 600ms - it may still be loading the later ones while it displays the first ones. (In particular, most GUI frameworks I've seen can't fill 80,000 rows that quickly even without a database being involved.)

You could try doing the same thing, assuming the API you're using lets you get at results in a streaming fashion (instead of transferring everything into memory before the call returns).

笙痞 2024-08-01 04:02:44

我自己在基本表(无连接)上尝试过,发现即使您单击“显示全部”复选框,SQLyog 也不会立即将所有结果显示在网格上,您可以通过将滚动按钮移动到最低区域来尝试一下,你会注意到 sqlyog 会放慢一些时间,并带来更多结果来显示。

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

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

顺便说一句,来自 sun 的官方 MySql GUI 工具 使用 Delphi 构建;- )

I have tried this my self on basic table (no join), and found even if you click on "Show All" checkbox, SQLyog will not bring all the results on grid immediately, try it your self by moving scroll button to lowest area, you will notice sqlyog will slow down for few moments, and bring more result to show.

also ODBC known to be slower because it add more layer to the native access,so try with MyDac from DevArt which is using direct access to mysql (even without mysql client library).

and as most of all said, never try to show the user 80,000 record by one time.

BTW, the official MySql GUI tools from sun built using Delphi ;-)

杯别 2024-08-01 04:02:44

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

FWIW 我使用 MyDac 已经很多年了,我真的很满意(性能/奖品/支持)

I guess it is because SQLyog uses native MySQL C API (direct connection) whereas you are using an ODBC connector.
Did you tried 3rd party connectors like MyDAC from Devart ? You can grab a free trial from there and test your application with it.

FWIW I'm using MyDac for years now and I'm really pleased with (performance / prize / support)

禾厶谷欠 2024-08-01 04:02:44

正如其他人所说,这可能是因为 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 按需加载数据,因此第一次访问它会很慢,但后续时间会花费更长的时间等等。但是,它将取决于您的需求。

华泰

As others have said, it's likely because SQLyog isn't loading all the records up, and probably limiting it to 200 or so.

In order to resolve this performance issue, you can use sneaky tricks. Since you're basically loading a cache of the dataset into your application at startup, you could thread this. It would still take 6 or 8 seconds to load, but your application would still start up and the UI would be usable. If someone did something that required the cache before it was loaded, you could simply display the hourglass cursor, or a message saying "one moment please..." until the cache was ready.

One thing to be aware of when doing data access in a thread is that you usually will need to create a separate database connection in your thread. Something like this:

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;

That's the basic idea, anyway. There are other ways that are more complex but technically superior, like making the GlobalSettings.CachedDataset load the data on-demand, so the first time you access it it'll be slow, but subsequent times will take longer, etc. However, it'll depend on your needs.

HTH

圈圈圆圆圈圈 2024-08-01 04:02:44

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

You can use LIMIT 0,1000 on query, then change it when user reaches far end - by checking in OnAfterScroll event.

相对绾红妆 2024-08-01 04:02:44

在我看来,您应该仔细考虑您的应用程序和/或数据库架构 - 在处理 80K 记录时这没有什么好处。 尝试缩小你的查询范围 - 如果你不让你的生活更简单 - 没有人会 $)

In my opinion you should think twice about your application and/or database architecture - it's no good, in dealing with 80K records. Try to narrow your query - if you wouldn't make your life simpler - nobody would $)

城歌 2024-08-01 04:02:44

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

SQLyog won't probably load all 80000 rows at once, at least some db tools which I use do "load on demand" when scrolling. If you need absolutely to get all the records at once, considering using thread to execute the query and populate the internal array.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文