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=""' + ';Use Encryption for Data=False;Tag with column collation when po' + 'ssible=False;MARS Connection=False;DataTypeCompatibility=0;Trust' + ' Server Certificate=False;Server SPN="";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
相关产品推荐
相关产品推荐

