2013-08-02 21 views
2

我有一个包含5000万条记录,但结构紧凑(id,int1,int1,int2,int3)的表。所有相关指标均已实施。反复查询大表的最快方法

我需要为每个用户交互查询约50次。这大约需要5秒钟,对数据库服务器使用常规准备好的查询。所有的查询都是简单的选择。

我的问题是:我能做些什么来加速这个,甚至花费更多的内存?查询的查找方法不够灵活,直接在查询中使用过滤器速度很慢。

我正在主查询是

select knowledge_id, knowledge_family_id, tag_level, tag_order, 
    total_title_direct_words, total_title_parenthesis_words from knowledge_tags 
    where dictionary_word_id = XX order by tag_level, tag_order 

任何人都可以提出一个策略? TVirtualTable会提高速度吗?

+2

要回答这个问题,我们需要有关性质的更多信息这50个查询中。他们都是单行SELECTs?你可以将一些查询组合成更大,更复杂的查询吗? –

+0

对不起。所有查询都是简单的选择。随着每个查询的结果我建立一个TDictionary添加结果。我不认为有一种方法可以将它分组为更少的查询。 –

+0

'所有查询都是简单的选择'没有限制像'where ID in'或其他? – bummi

回答

1

我我看来,这将是更快的加载TClientDataSet整个数据,并使用FINDKEY来寻求这些记录。

要使用FindKey()你必须定义指标是这样的:

Cds.IndexDefs.ADD('IDX1', 'FieldA;FieldB',[]); 
Cds.IndexName := 'IDX1'; 
if Cds.FindKey([A,B]) then begin 
    //Do something 
end; 

您还可以创建多个索引,并使用它,只要你想:

Cds.IndexDefs.ADD('IDX1', 'FieldA;FieldB',[]); 
Cds.IndexDefs.ADD('IDX2', 'FieldD;FieldB',[]); 
Cds.IndexDefs.ADD('IDX3', 'FieldA;FieldC',[]); 

if SeekAB then 
    Cds.IndexName := 'IDX1' 
else if SeekDB then 
    Cds.IndexName := 'IDX2' 
else 
    Cds.IndexName := 'IDX3'; 
+0

我用单个查询替换了主查询执行重复,在应用程序启动时将整个数据集加载到内存中。要查询我正在使用“定位”并使用“下一步”导航,直到找到不相关的记录。数据集以我可以做到的方式排序。 5秒已经下降到0.5秒。我相信这是道理。由于加载数据集,唯一的警告是启动时间。另外,在将新数据添加到查询表后,我必须实现一种透明方式来向打开的查询添加新记录。数据可用性会有所延迟,但速度的提高是有道理的。 –

+0

@MiguelE您是否尝试过使用:'TADOQuery'>'TADOProvider'>'TClientDataSet' – EProgrammerNotFound

+0

@MiguelE另外,如果您的提供程序支持'SEEK',则此方法可用于查询。它具有带索引的FindKey。 – EProgrammerNotFound

3

考虑到整个表加载到内存是不是一个问题,我建议:

  1. 执行查询以选择所有记录
  2. 走在数据集中的一次性的记录复制到TObjectList <TMyRecord>的实例,其中TMyRecord是可包含数据集记录的所有字段的类;因此您现在拥有的是目标列表中的数据集的副本
  3. 如果可能,请对列表进行排序(或选择正确的顺序),以便在需要时运行二进制搜索
  4. 释放数据集并只在名单上工作。

在这种情况下,您将避免所有数据集开销,并且每次搜索都会更快。

的TMyRecord的一个例子是:

interface 

type 
    TMyRecord = class 
    private 
    FId: Integer; 
    FCol1: Integer; 
    FCol2: Integer; 
    FCol3: Integer; 
    FCol4: Integer; 
    public 
    constructor Create(aId, aCol1, aCol2, aCol3, aCol4: Integer); 
    property Id: Integer read FId write FId; 
    property Col1: Integer read FCol1 write FCol1; 
    property Col2: Integer read FCol2 write FCol2; 
    property Col3: Integer read FCol3 write FCol3; 
    property Col4: Integer read FCol4 write FCol4; 
    end; 

implementation 

constructor TMyRecord.Create(aId, aCol1, aCol2, aCol3, aCol4: Integer); 
begin 
    FId := aId; 
    FCol1 := aCol1; 
    FCol2 := aCol2; 
    FCol3 := aCol3; 
    FCol4 := aCol4; 
end; 
+1

我认为存储在通用列表中的记录可能会更好地完成这项工作...... – TLama

+0

@TLama:在使用记录时,您有很多内存传输,因为记录是值类型。类是参考类型,所以传输的数据只是一个处理器字,并且在很多时候它使用一个CPU寄存器。考虑到速度是这里主要关心的问题,我不同意。 – AlexSC

+1

如果复制它们,记录只会导致内存传输。 TList 不会导致副本,也不会处理const参数。类有额外的内存开销,将在50M记录之后加起来。 – afrazier