快速SQL查询但结果检索速度慢

时间:2012-02-08 14:09:38

标签: delphi advantage-database-server

我正在使用Sybase的Advantage Database Server,目前还有一个很快的快速左连接查询,运行速度非常快。问题是在运行查询后我想将结果放入一个字符串中。我检索了55000个条目的数据集。 现在最多需要16秒。将它放入字符串中。我的查询只花了8毫秒才能运行。我的第一个尝试是:

    aADSQuery.Open
    aADSQuery.First
    WHILE not aADSQuery.eof do
    begin
       s := s + aADSQuery.FieldbyName('Name').asString+',';
       aADSQuery.Next;
    end;

之后,我试过这个以避免aADSQuery.next,但aADSQuery.RecordCount采取了 我9秒。

    aADSQuery.Open
    aADSQuery.First
    Count := aADSQuery.RecordCount;
    for i:=0 to count-1 do
    begin
      aADSQuery.RecNo := i;
      aADSQuery.FieldbyName('Name').AsString; 
    end;

数据库已编制索引,条目ID为主键,其他列则为indizes。 我考虑创建一个视图来计算我的条目以避免记录计数,这可能与sql计数完全相同。但是视图中的条目计数与之前的时间相同。如果我使用sql 依靠130000个条目计算我的基表,它只需要200毫秒。但是,如果我对结果表进行计数,而不使用视图则需要9秒。我觉得它是,因为没有新的临时结果表的indizes。有谁知道如何以正确的方式处理这类问题或如何获得更快的结果计数?

非常感谢

4 个答案:

答案 0 :(得分:13)

使用一些基于缓冲区的类(例如TStringStream)来填充字符串。这样可以避免String连接的缓慢重新分配(s := s + foo)。

不要在循环中使用aADSQuery.FieldbyName('Name').AsString。这很慢。 而是像这样创建一个局部变量F

var
  F: TField;

F := aADSQuery.FieldbyName('Name');
for i:=0 to count-1 do
begin
  aADSQuery.RecNo := i;
  F.AsString; 
end;

我认为使用aADSQuery.Next比使用RecNo

更快
procedure Test;
var
  F: TField;
  Buf: TStringStream;
  S: string;
begin
  aADSQuery.DisableControls;
  try
    aADSQuery.Open;
    F := aADSQuery.FieldbyName('Name');
    Buf := TStringStream.Create('');
    try
      while not aADSQuery.Eof do
      begin
        Buf.WriteString(F.AsString + ',');
        aADSQuery.Next;
      end;
      S := Buf.DataString;
    finally
      Buf.Free;
    end;
  finally
    aADSQuery.EnableControls;
  end;
end;

您可以在服务器端生成该字符串并将其返回给客户端,而无需在客户端构造任何字符串:

DECLARE @Names NVARCHAR(max)
SELECT @Names = ''
SELECT @Names = @Names + ',' + ISNULL([Name], '') FROM MyTable
SELECT @Names

您还可以通过设置TAdsQuery.AdsTableOptions来优化效果。确保AdsFilterOptions设置为IGNORE_WHEN_COUNTINGAdsFreshRecordCount设置为False

答案 1 :(得分:2)

从OP中,我不完全清楚目标是找到记录总数还是向用户显示数据。如果要显示数据,那么将55,000条记录的所有数据附加到单个字符串中可能不是最好的方法。如果您对在Advantage Data Architect中运行查询的性能感到满意,那么使用类似的方法并将数据存储在某种网格中可能是有意义的。

例如,将TDataSource与TDBGrid关联,并将查询绑定到数据源:

AdsQuery1.Open;
DataSource1.DataSet:=AdsQuery1;
DBGrid1.DataSource:=DataSource1;

数据感知网格将只获取填充网格所需的数据,并在用户通过网页时按需请求数据。

编辑当您请求记录计数时,服务器必须解析整个结果集。如果您使用的是Advantage Local Server,并且数据驻留在网络服务器上,则读取网络中的所有数据将涉及额外的成本。如果您使用的是Advantage Database Server(客户端/服务器版本),则处理将在服务器上进行,并且速度可能会快得多。

它当然取决于查询,但解析结果集9秒可能会过长。在Advantage Data Architect中,您可以检查查询的优化。 SQL菜单下有一个“显示计划”选项,SQL实用程序中的工具栏上有一个按钮,用于显示查询计划。可能是您缺少必要的索引。

答案 2 :(得分:0)

为什么不执行你需要的服务器端并返回结果?

此外,在这种情况下:

  • 每次强制Delphi重新分配字符串。如果你知道它可以达到的最大尺寸,你应该在之前预先分配字符串大小,然后在完成时“纠正”它。
  • FieldByName()很慢 - 它必须为每次调用执行查找。定义您将用于数据集的字段。
  • 如果记录“大”,网络性能可能很重要。您可以将MTU设置为更大的值,以更好地利用当今的千兆网络。

答案 3 :(得分:0)

所以最后,我发现了我的错误,但有些事我不明白。 首先,我在连接查询中更改了我的左连接sql查询。这使我的记录数量更快,如果我下次使用它,现在它更快。所以在那之后我检查了每列的表格类型。而且我发现,如果没有必要,对字符列使用固定大小并不是很有效。在我的情况下,我已经为20列选择了100的大小,但是我的列的大小从第1列增加到20,每步增加3。因此,第20列的最大大小为60,第1列有3个字符。(这些是我的搜索列)这使得我的while子句的速度提高了两倍。随着这些变化。我可以在5500毫秒内获得55000个条目。现在我改变了桌面设计。我把所有东西放在一张桌子里,我不再需要加入了。至少目前不是这样。我使用了正常的Select .. From .. Where子句。我将这55000个输入结果的时间再次减少到2500毫秒。这对我来说太好了。 所以唯一的问题仍然是,如果我使用不同的sql查询,为什么在执行ADSQuery.open后获取数据会有很大的不同。我认为它可能会影响执行sql查询的时间,但它也影响了 结果提取。