You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在Delphi中通过FireDAC的FDQuery获取Firebird 2.5查询性能信息?

用FireDAC的FDQuery获取Firebird 2.5查询性能信息(对应IBExpert指标)

嘿,刚好对这个场景很熟悉,我来给你一步步讲清楚怎么拿到和IBExpert一模一样的那些查询性能数据,完全基于FireDAC组件实现:

一、先搞定基础时间指标(Prepare/Execute/Fetch Time)

FDQuery本身就内置了这些时间属性,直接读就行,和IBExpert显示的一一对应:

  • Prepare Time:对应FDQuery.PrepareTime,单位是毫秒
  • Execute Time:对应FDQuery.ExecutionTime,单位毫秒
  • Avg Fetch Time:可以用总Fetch时间FDQuery.FetchTime除以查询返回的记录数(或者你自己统计的Fetch批次)来计算出平均值

举个实际代码例子:

FDQuery1.SQL.Text := 'SELECT * FROM YOUR_TARGET_TABLE';
FDQuery1.Open;

// 输出基础时间统计
ShowMessage(Format(
  '------ Performance info ------'#13+
  'Prepare time = %d ms'#13+
  'Execute time = %d ms'#13+
  'Avg fetch time = %.2f ms',
  [FDQuery1.PrepareTime,
   FDQuery1.ExecutionTime,
   FDQuery1.FetchTime / FDQuery1.RecordCount]));

二、获取内存、磁盘IO这类进阶统计

这些是Firebird服务器层面的运行数据,有两种可靠的获取方式:

方式1:用FDConnection的GetStatistics方法(最直接,和IBExpert输出一致)

FireDAC的TFDConnection提供了GetStatistics方法,能直接拿到和IBExpert几乎完全一样的统计条目,包括内存、缓存读写、磁盘IO这些:

var
  StatsList: TStrings;
begin
  StatsList := TStringList.Create;
  try
    // 第二个参数传True获取详细统计数据
    FDConnection1.GetStatistics(StatsList, True);
    // 遍历筛选你需要的指标,直接输出或者存起来
    for var I := 0 to StatsList.Count - 1 do
    begin
      if Pos('Current memory', StatsList[I]) > 0 then
        Memo_PerfInfo.Lines.Add(StatsList[I]);
      if Pos('Max memory', StatsList[I]) > 0 then
        Memo_PerfInfo.Lines.Add(StatsList[I]);
      if Pos('Reads from disk to cache', StatsList[I]) > 0 then
        Memo_PerfInfo.Lines.Add(StatsList[I]);
      if Pos('Fetches from cache', StatsList[I]) > 0 then
        Memo_PerfInfo.Lines.Add(StatsList[I]);
    end;
  finally
    StatsList.Free;
  end;
end;

运行后你会看到和IBExpert里一模一样的条目,比如Current memory = 14717320这种格式。

方式2:查询Firebird的监控表(更灵活,自定义粒度)

Firebird 2.5内置了监控系统表,比如MON$STATEMENTSMON$MEMORY_USAGE,可以通过FDQuery直接查询这些表,获取更细粒度的统计数据。不过要注意,访问这些表需要连接用户有MONITOR角色或者SYSDBA权限。

示例代码:

FDQuery1.SQL.Text := 
  'SELECT '+
  '  MON$PREPARE_TIME AS PrepareTime, '+
  '  MON$EXECUTE_TIME AS ExecuteTime, '+
  '  MON$FETCH_TIME AS TotalFetchTime, '+
  '  MON$MEMORY_USED AS CurrentMemory, '+
  '  MON$MEMORY_MAX AS MaxMemory, '+
  '  MON$READS_DISK AS ReadsFromDisk, '+
  '  MON$FETCHES_CACHE AS FetchesFromCache '+
  'FROM MON$STATEMENTS '+
  'WHERE MON$STATEMENT_ID = :StmtID';

// 绑定当前FDQuery的语句ID,FireDAC的Handle属性就是Firebird的语句句柄
FDQuery1.ParamByName('StmtID').AsInteger := FDQuery1.Handle;
FDQuery1.Open;

if not FDQuery1.IsEmpty then
begin
  // 这里可以把数据转换成你想要的格式,比如IBExpert的样式
  Memo_PerfInfo.Lines.Add('------ Performance info ------');
  Memo_PerfInfo.Lines.Add(Format('Prepare time = %d ms', [FDQuery1.FieldByName('PrepareTime').AsInteger div 1000]));
  Memo_PerfInfo.Lines.Add(Format('Execute time = %d ms', [FDQuery1.FieldByName('ExecuteTime').AsInteger div 1000]));
  Memo_PerfInfo.Lines.Add(Format('Avg fetch time = %.2f ms', [FDQuery1.FieldByName('TotalFetchTime').AsInteger / 1000 / FDQuery1.RecordCount]));
  Memo_PerfInfo.Lines.Add(Format('Current memory = %d', [FDQuery1.FieldByName('CurrentMemory').AsInteger]));
  Memo_PerfInfo.Lines.Add(Format('Max memory = %d', [FDQuery1.FieldByName('MaxMemory').AsInteger]));
  Memo_PerfInfo.Lines.Add(Format('Reads from disk to cache = %d', [FDQuery1.FieldByName('ReadsFromDisk').AsInteger]));
  Memo_PerfInfo.Lines.Add(Format('Fetches from cache = %d', [FDQuery1.FieldByName('FetchesFromCache').AsInteger]));
end;

注意:Firebird监控表返回的时间单位是微秒,所以要除以1000转换成毫秒,和IBExpert的格式对齐。

三、几个关键注意点

  • 权限要求:如果用监控表的方式,必须确保连接用户有MONITOR角色或者SYSDBA权限,否则会查不到数据
  • 统计时效性:这些统计数据是针对当前连接/当前语句的,一定要在查询执行完成后立即获取,不然会被后续的数据库操作覆盖
  • 格式转换:IBExpert里的内存显示可能用了千位分隔符(比如14717320其实是14717320),你可以自己处理字符串格式来对齐显示

内容的提问来源于stack exchange,提问作者Franky Brandt

火山引擎 最新活动