You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi Alexandria 11.1插入带大量查找字段的数据集时异常延迟

Delphi Alexandria 11.1中带查找字段的TADOQuery插入行性能急剧下降(对比XE7)

我将公司项目从Delphi XE7迁移到Alexandria 11.1后,部分数据库规模较大的客户反馈常用表单打开延迟明显。排查发现延迟集中在向主TClientDataset插入行的操作中,该数据集包含约50个字段,其中5个是关联到另一含10万行数据的ADOQuery的查找字段。

为定位问题,我搭建了测试项目:一个包含10万行5字段的ADOQuery(luPersons),另一个ADOQuery(qBooks)设置了5个关联它的查找字段。插入一行并为关键字段赋值后,Alexandria版本耗时约40ms,而XE7版本仅需2ms。

查找字段数量增加或为其他字段赋值时,耗时会进一步上升。项目部分场景下,XE7中3-4秒的加载时间在Alexandria中升至12-15秒,Release版本中该现象更为显著。

我尝试调试VCL代码并对比两个版本的Ado和dsnap文件夹文件,未找到差异;谷歌搜索也未发现类似报告。现想确认这是否是新版本Delphi的Bug,或是遗漏了新配置选项,恳请有类似经验的人士提供相关信息。


复现用SQL脚本

CREATE TABLE [dbo].[Persons](
    [ID] [int] NOT NULL,
    [ModifiedDate] [datetime] NULL,
    [FirstName] [varchar](50) NULL,
    [LastName] [varchar](50) NULL,
    [EMail] [varchar](30) NULL,
    [PhoneNumber] [varchar](15) NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[Books](
    [BookID] [int] NOT NULL,
    [Title] [nchar](50) NOT NULL,
    [PersonID] [int] NOT NULL,
 CONSTRAINT [PK_Books] PRIMARY KEY CLUSTERED 
(
    [BookID] ASC
) ON [PRIMARY]
) ON [PRIMARY]

DECLARE @RowCount int = 100000,
        @Index int = 1

WHILE (@Index <= @RowCount)
BEGIN
    INSERT INTO Persons (ID, ModifiedDate, FirstName, LastName, EMail, PhoneNumber)
           VALUES (@Index, getdate(), 'FirstName' + CAST(@Index AS varchar(10)), 'LastName' + CAST(@Index AS varchar(10)), 'EMail' + CAST(@Index AS varchar(10)), CAST(@Index AS varchar(10)))
    SET @Index += 1
END

复现用DFM代码

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 177
  ClientWidth = 179
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = 'Segoe UI'
  Font.Style = []
  OnCreate = FormCreate
  TextHeight = 15
  object BitBtn1: TBitBtn
    Left = 56
    Top = 144
    Width = 75
    Height = 25
    Caption = 'Load'
    TabOrder = 0
    OnClick = BitBtn1Click
  end
  object luPersons: TADOQuery
    Connection = ADOConnection1
    CursorType = ctStatic
    Parameters = <>
    SQL.Strings = (
      'SELECT *'
      'FROM PERSONS')
    Left = 32
    Top = 72
    object luPersonsID: TIntegerField
      FieldName = 'ID'
      ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]
    end
    object luPersonsModifiedDate: TDateTimeField
      FieldName = 'ModifiedDate'
    end
    object luPersonsFirstName: TStringField
      FieldName = 'FirstName'
      Size = 50
    end
    object luPersonsLastName: TStringField
      FieldName = 'LastName'
      Size = 50
    end
    object luPersonsEMail: TStringField
      FieldName = 'EMail'
      Size = 30
    end
    object luPersonsPhoneNumber: TStringField
      FieldName = 'PhoneNumber'
      Size = 15
    end
  end
  object ADOConnection1: TADOConnection
    ConnectionString = 
      'Provider=SQLNCLI11.1;Persist Security Info=False;User ID=sa;Pass' +
      'word=password;Initial Catalog=testDB;Data Source=DATABASE;'
      'Use Procedure for Prepare=1;Auto Translate=True;Pack' +
      'et Size=4096;Workstation ID=Workstation;Initial File Name=&quot;&quot;' +
      ';Use Encryption for Data=False;Tag with column collation when po' +
      'ssible=False;MARS Connection=False;DataTypeCompatibility=0;Trust' +
      ' Server Certificate=False;Server SPN=&quot;&quot;;Application Intent=READW' +
      'RITE'
    Provider = 'SQLNCLI11.1'
    Left = 80
    Top = 16
  end
  object qBooks: TADOQuery
    Connection = ADOConnection1
    CursorType = ctStatic
    Parameters = <>
    SQL.Strings = (
      'SELECT *'
      'FROM BOOKS')
    Left = 128
    Top = 72
    object qBooksBookID: TIntegerField
      FieldName = 'BookID'
      ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]
    end
    object qBooksTitle: TWideStringField
      FieldName = 'Title'
      FixedChar = True
      Size = 50
    end
    object qBooksPersonID: TIntegerField
      FieldName = 'PersonID'
    end
    object qBooksModifiedDate: TDateTimeField
      FieldKind = fkLookup
      FieldName = 'ModifiedDate'
      LookupDataSet = luPersons
      LookupKeyFields = 'ID'
      LookupResultField = 'ModifiedDate'
      KeyFields = 'PersonID'
      Lookup = True
    end
    object qBooksFirstName: TStringField
      FieldKind = fkLookup
      FieldName = 'FirstName'
      LookupDataSet = luPersons
      LookupKeyFields = 'ID'
      LookupResultField = 'FirstName'
      KeyFields = 'PersonID'
      Size = 50
      Lookup = True
    end
    object qBooksLastName: TStringField
      FieldKind = fkLookup
      FieldName = 'LastName'
      LookupDataSet = luPersons
      LookupKeyFields = 'ID'
      LookupResultField = 'LastName'
      KeyFields = 'PersonID'
      Size = 50
      Lookup = True
    end
    object qBooksEMail: TStringField
      FieldKind = fkLookup
      FieldName = 'EMail'
      LookupDataSet = luPersons
      LookupKeyFields = 'ID'
      LookupResultField = 'EMail'
      KeyFields = 'PersonID'
      Size = 30
      Lookup = True
    end
    object qBooksPhoneNumber: TStringField
      FieldKind = fkLookup
      FieldName = 'PhoneNumber'
      LookupDataSet = luPersons
      LookupKeyFields = 'ID'
      LookupResultField = 'PhoneNumber'
      KeyFields = 'PersonID'
      Size = 15
      Lookup = True
    end
  end
end

复现用PAS源码

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls, Vcl.Buttons;

type
  TForm1 = class(TForm)
    luPersons: TADOQuery;
    ADOConnection1: TADOConnection;
    luPersonsID: TIntegerField;
    luPersonsModifiedDate: TDateTimeField;
    luPersonsFirstName: TStringField;
    luPersonsLastName: TStringField;
    luPersonsEMail: TStringField;
    luPersonsPhoneNumber: TStringField;
    qBooks: TADOQuery;
    qBooksBookID: TIntegerField;
    qBooksTitle: TWideStringField;
    qBooksPersonID: TIntegerField;
    qBooksModifiedDate: TDateTimeField;
    qBooksFirstName: TStringField;
    qBooksLastName: TStringField;
    qBooksEMail: TStringField;
    qBooksPhoneNumber: TStringField;
    BitBtn1: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses System.DateUtils;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
    starttime, endtime: TTime;
begin
    starttime := Time;
    qBooks.Open;

    qBooks.Insert;
    qBooksBookID.AsInteger := 1;
    qBooksPersonID.AsInteger := 1;

    endtime := Time;

    ShowMessage(MilliSecondsBetween(endtime, starttime).ToString + ' ' + FormatDateTime('hh:mm:ss.zzz', starttime) +
                                                                   ' ' + FormatDateTime('hh:mm:ss.zzz', endtime));
    qBooks.Close;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    luPersons.Open;
end;

end.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:55:31