如何在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$STATEMENTS、MON$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




