DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: kebingoo
今日帖子: 3
在线用户: 1
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/11/28 14:37:28
标题:
关于Delphi7下用Unidac查询SQLite,查询时间时长时短的问题。请大牛帮忙分析分析 浏览:2053
加入我的收藏
楼主: 先需要从一个SQLite数据库里查询是否有该卡卡号。查询需要在50ms内完成。

SQLite数据库有3个字段,A(索引),B(索引),C。数据大约30W条。
按A或者B查询,返回C。
我写了个动态库方法。
function ExistsBlackList(CardID: PAnsiChar; OBUID: PAnsiChar; AProvinceID: PAnsiChar): Integer; stdcall;
var
  UniConnection: TUniConnection;
  UniQuery: TUniQuery;
  DBName: string;
  CardID_Temp, OBUID_Temp, ProvinceID_Temp: string;
  StartTime, TotleTime: Double;
  CostTime: string;
begin
  Result := 0;
  StartTime := GetTickCount;
  TotleTime := GetTickCount;
  try
    CardID_Temp := CardID;
    CardID_Temp := Trim(CardID_Temp);
    OBUID_Temp := OBUID;
    OBUID_Temp := Trim(OBUID_Temp);
    ProvinceID_Temp := Trim(AProvinceID);

    UniConnection := TUniConnection.Create(nil);
    if (ProvinceID_Temp = '') or (ProvinceID_Temp = 'all') then
      DBName := 'all.db'
    else
      DBName := ProvinceID_Temp + '.db';
    try

      with UniConnection do
      begin

      //读取数据库配置文件
        with TIniFile.Create(ExtractFileDir(ParamStr(0)) + '/BlackListConfig.ini') do
        begin
          try
          ProviderName := 'sqlite';
          Database := ExtractFileDir(ParamStr(0)) + '\BlackListFiles' + ReadString('SQLite',
          'Version', '') + '\' + DBName;
          finally
          Free;
          end;
        end;
        LoginPrompt := False;
        Connected := True;
      end;

      CostTime := CostTime + 'ConnectDB-' + FloatToStr(GetTickCount - StartTime) + #13#10;
      StartTime := GetTickCount;

      UniQuery := TUniQuery.Create(nil);
      try
        with UniQuery do
        begin
          Connection := UniConnection;
          Close;

          if (CardID_Temp <> '') and (OBUID_Temp = '') then
          begin
          SQL.Text := 'SELECT CardType FROM PETCRegionBlackList WHERE CardID = ''' + CardID_Temp + '''';
          Open();
          if RecordCount > 0 then
          Result := FieldByName('CardType').AsVariant;

          WriteLog('-ExistsBlackList-CardID_Temp-' + IntToStr(Result) + '-' + FloatToStr(GetTickCount - StartTime) + 'ms');
          end
          else if (CardID_Temp = '') and (OBUID_Temp <> '') then
          begin
          SQL.Text := 'SELECT CardType FROM PETCRegionBlackList WHERE OBUID = ''' + OBUID_Temp + '''';
          Open();
          if RecordCount > 0 then
          Result := FieldByName('CardType').AsVariant;

          WriteLog('-ExistsBlackList-OBUID_Temp-' + IntToStr(Result) + '-' + FloatToStr(GetTickCount - StartTime) + 'ms');
          end
          else if (CardID_Temp <> '') and (OBUID_Temp <> '') then
          begin
          SQL.Text := 'SELECT CardType FROM PETCRegionBlackList WHERE CardID = ''' + CardID_Temp +
          ''' AND OBUID = ''' + OBUID_Temp + '''';
          Open();
          if RecordCount > 0 then
          Result := FieldByName('CardType').AsVariant;

          WriteLog('-ExistsBlackList-CardID_Temp/OBUID_Temp-' + IntToStr(Result) + '-' + FloatToStr(GetTickCount - StartTime) + 'ms');
          end;
        end;

      CostTime := CostTime + 'Select-' + FloatToStr(GetTickCount - StartTime) + #13#10;
      StartTime := GetTickCount;

      finally
        UniQuery.Free;
      end;
    finally
      UniConnection.Free;
    end;

    if (GetTickCount - TotleTime) > 50 then
      WriteDebugLog(CostTime + 'Totle-' + FloatToStr(GetTickCount - TotleTime));

  except
    on E: Exception do
    begin
      Result := -1;
      WriteErrorLog('-ExistsBlackList-' + E.Message);
    end;
  end;
end;



运行这个方法必须在50ms以内。

我写了一个Demo来测试。

procedure TForm1.Button3Click(Sender: TObject);
var
  Interval, Times, I, J: Integer;
  StartTime, ContinueTime: Double;
  ACardID, AResult: string;

  function CreateRandomNum: string;
  var
    NumTemp: string;
    I, J: Integer;
  begin
    Result := '';
    for I := 1 to 4 do
    begin
      NumTemp := IntToStr(Random(99999));
      if Length(NumTemp) < 5 then
        for J := 1 to 5 - Length(NumTemp) do
          NumTemp := NumTemp + '0';
      Result := Result + NumTemp;
    end;
  end;

begin
  Label4.Caption := '';
  Randomize;
  Interval := StrToInt(Trim(Edit2.Text)); //暂时没用
  Times := StrToInt(Trim(Edit3.Text));  //循环次数
  for I := 0 to Times do
  begin
    ACardID := CreateRandomNum;   //随机卡号
    StartTime := GetTickCount;
    case RadioGroup1.ItemIndex of
      0: AResult := IntToStr(ExistsBlackList(PAnsiChar(ACardID), '', 'all'));
      1: AResult := IntToStr(ExistsBlackList('', PAnsiChar(ACardID), 'all'));
    end;
    ContinueTime := GetTickCount - StartTime;
    Memo1.Lines.Add(DateTimeToStr(Now) + ' 卡号:' + ACardID + ' 结果:' + AResult + ' 用时:' + FloatToStr(ContinueTime) + 'ms');
    if ContinueTime > StrToFloat(Edit4.Text) then
    begin
      Memo2.Lines.Add(DateTimeToStr(Now) + '卡号:' + ACardID + ' 结果:' + AResult + ' 用时:' + FloatToStr(ContinueTime) + 'ms');
//      Break;
    end;
    for J := 0 to 100000 do
    begin
      CreateRandomNum;
    end;
//    Sleep(StrToInt(Edit2.Text));
    Application.ProcessMessages;
    Label4.Caption := IntToStr(I + 1);
  end;
end;



后面发现,运行了24000次,大约有30次超过了50ms,其余大多都是0ms,或者15、16ms。

下面是超过50ms的日志,记录着哪一块耗时多少。

2014-11-28 13:05:31  ConnectDB-0
Select-94
Totle-94

2014-11-28 13:10:37  ConnectDB-0
Select-109
Totle-109

2014-11-28 13:11:53  ConnectDB-79
Select-15
Totle-94

2014-11-28 13:15:37  ConnectDB-250
Select-0
Totle-250

2014-11-28 13:15:37  ConnectDB-78
Select-16
Totle-94

2014-11-28 13:15:40  ConnectDB-0
Select-63
Totle-63

2014-11-28 13:19:57  ConnectDB-15
Select-47
Totle-62

2014-11-28 13:21:30  ConnectDB-0
Select-63
Totle-63

2014-11-28 13:22:20  ConnectDB-172
Select-0
Totle-172

2014-11-28 13:29:28  ConnectDB-0
Select-62
Totle-62

2014-11-28 13:30:40  ConnectDB-0
Select-62
Totle-62

2014-11-28 13:31:19  ConnectDB-0
Select-62
Totle-62

2014-11-28 13:36:10  ConnectDB-0
Select-62
Totle-62

2014-11-28 13:36:11  ConnectDB-62
Select-0
Totle-62

2014-11-28 13:37:02  ConnectDB-1141
Select-15
Totle-1156

2014-11-28 13:39:32  ConnectDB-0
Select-63
Totle-63

2014-11-28 13:45:19  ConnectDB-0
Select-78
Totle-78

2014-11-28 13:53:10  ConnectDB-0
Select-63
Totle-63

2014-11-28 13:53:11  ConnectDB-0
Select-578
Totle-578

2014-11-28 13:53:14  ConnectDB-0
Select-563
Totle-563

2014-11-28 13:53:15  ConnectDB-0
Select-281
Totle-281

2014-11-28 13:53:16  ConnectDB-0
Select-594
Totle-594

2014-11-28 13:53:17  ConnectDB-16
Select-203
Totle-219

2014-11-28 13:53:18  ConnectDB-0
Select-78
Totle-78

2014-11-28 13:53:19  ConnectDB-0
Select-219
Totle-219

2014-11-28 13:53:22  ConnectDB-0
Select-188
Totle-188

2014-11-28 13:53:36  ConnectDB-0
Select-109
Totle-109

2014-11-28 13:53:46  ConnectDB-0
Select-438
Totle-438

2014-11-28 13:53:48  ConnectDB-0
Select-985
Totle-985

2014-11-28 13:53:54  ConnectDB-0
Select-500
Totle-500

2014-11-28 13:53:55  ConnectDB-0
Select-921
Totle-921

2014-11-28 13:54:00  ConnectDB-0
Select-78
Totle-78

2014-11-28 13:55:43  ConnectDB-15
Select-47
Totle-62

2014-11-28 13:55:44  ConnectDB-109
Select-0
Totle-109

2014-11-28 13:57:37  ConnectDB-0
Select-78
Totle-78

2014-11-28 14:06:15  ConnectDB-47
Select-16
Totle-63

2014-11-28 14:16:20  ConnectDB-0
Select-109
Totle-109

2014-11-28 14:19:09  ConnectDB-0
Select-62
Totle-62

2014-11-28 14:21:42  ConnectDB-0
Select-94
Totle-94

2014-11-28 14:21:50  ConnectDB-0
Select-78
Totle-78

2014-11-28 14:27:37  ConnectDB-0
Select-63
Totle-63

2014-11-28 14:30:50  ConnectDB-266
Select-0
Totle-266
----------------------------------------------
-
作者:
男 tpcnyou (tpcnyou) ★☆☆☆☆ -
普通会员
2014/11/28 14:51:11
1楼: 建议
如果数据库大小是固定的,非在增长
数据库在dll初始化的时候直接放到内存中,这样不用每次调用dll的时候就加载下数据库
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/11/28 15:05:06
2楼: @tpcnyou (tpcnyou)
请问是先LoadLibraryDLL,然后再调用方法么?
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/11/28 15:36:36
3楼: 换了动态加载DLL,又测试了1W条,还是出现了10个超时的

procedure TForm1.Button3Click(Sender: TObject);
var
  Interval, Times, I, J: Integer;
  StartTime, ContinueTime: Double;
  ACardID, AResult: string;
  DLL: Cardinal;
  PP: TExistsBlackList;

  function CreateRandomNum: string;
  var
    NumTemp: string;
    I, J: Integer;
  begin
    Result := '';
    for I := 1 to 4 do
    begin
      NumTemp := IntToStr(Random(99999));
      if Length(NumTemp) < 5 then
        for J := 1 to 5 - Length(NumTemp) do
          NumTemp := NumTemp + '0';
      Result := Result + NumTemp;
    end;
  end;

begin
  Label4.Caption := '';
  Randomize;

  DLL := LoadLibrary('CheckBlacklist.dll');
  if DLL = 0 then
    Exit;
  try
    @PP := GetProcAddress(DLL, 'ExistsBlackList');
    if @PP = nil then
      Exit;

    Interval := StrToInt(Trim(Edit2.Text));
    Times := StrToInt(Trim(Edit3.Text));
    for I := 0 to Times do
    begin
      ACardID := CreateRandomNum;
      StartTime := GetTickCount;
      case RadioGroup1.ItemIndex of
        0: AResult := IntToStr(PP(PAnsiChar(ACardID), '', 'all'));
        1: AResult := IntToStr(PP('', PAnsiChar(ACardID), 'all'));
      end;
      ContinueTime := GetTickCount - StartTime;
      Memo1.Lines.Add(DateTimeToStr(Now) + ' 卡号:' + ACardID + ' 结果:' + AResult + ' 用时:' + FloatToStr(ContinueTime) + 'ms');
      if ContinueTime > StrToFloat(Edit4.Text) then
      begin
        Memo2.Lines.Add(DateTimeToStr(Now) + '卡号:' + ACardID + ' 结果:' + AResult + ' 用时:' + FloatToStr(ContinueTime) + 'ms');
  //      Break;
      end;
      for J := 0 to 100000 do
      begin
        CreateRandomNum;
      end;
  //    Sleep(StrToInt(Edit2.Text));
      Application.ProcessMessages;
      Label4.Caption := IntToStr(I + 1);
    end;
  finally
    FreeLibrary(dll);
  end;
end;



2014-11-28 15:00:37  ConnectDB-0
Select-93
Totle-93

2014-11-28 15:23:45  ConnectDB-0
Select-62
Totle-62

2014-11-28 15:24:01  ConnectDB-78
Select-0
Totle-78

2014-11-28 15:24:06  ConnectDB-141
Select-15
Totle-156

2014-11-28 15:24:43  ConnectDB-47
Select-15
Totle-62

2014-11-28 15:25:23  ConnectDB-0
Select-62
Totle-62

2014-11-28 15:26:12  ConnectDB-0
Select-78
Totle-78

2014-11-28 15:29:31  ConnectDB-0
Select-94
Totle-94
----------------------------------------------
-
作者:
男 hguhgu (满汉全席) ★☆☆☆☆ -
普通会员
2014/11/28 17:25:06
4楼:  不知道这种要求的意义何在,数据库的操作由于库本身负荷等原因,查询时间没有那么精准吧
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/11/29 10:58:02
5楼: 求大牛支招啊
我在想可不可以dll里加一个方法,create一个connection,返回connection的指针。以后每次查询的时候把connection的指针穿进去,就不用每次再重新打开数据库了。

现在又有问题了。dll的宿主程序可以调用到返回的指针,但再把指针当参数传给dll里的方法,报内存错误,估计是不能跨进程访问内存?请问我如果想实现这种方法该用什么技术?百度什么?
----------------------------------------------
-
作者:
男 tpcnyou (tpcnyou) ★☆☆☆☆ -
普通会员
2014/11/29 15:58:38
6楼: 你这个不稳定,跟多方面有关系
如果你这个动态库调用的是非常的频繁,就整成静态的,或直接弄成单例
我之前说的,你没有回答,这个数据库是不是还在增长,并且记录也不大,就放到内存中吧,速度会很快
动态库可以多做两个接口,一个打开数据库,一个关闭数据库
----------------------------------------------
-
作者:
男 yangweng (yangweng) ★☆☆☆☆ -
普通会员
2014/11/29 19:14:45
7楼: 如果数据库记录比较稳定的话,用MEMTABLE吧。这样快很多
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/12/1 9:27:09
8楼: @tpcnyou  数据库不增长,应该如何放到内存中呢?
另外做两个接口,打开和关闭,那得有个全局变量的connection吧?这个如何定义呢?
宿主程序是VC的,要是delphi的真就简单多了
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/12/1 9:27:44
9楼: 请大大告诉我应该百度什么技术就行了,谢谢哈
----------------------------------------------
-
作者:
男 souledge (souledge) ★☆☆☆☆ -
普通会员
2014/12/1 10:33:25
10楼: 你这个耗时主要在每次都去重连数据库!

你只需要在链接库内部创建一个全局的Connection,dll初始化的时候创建一次,dll卸载的时候释放,ExistsBlackList直接使用该Connection。

难道宿主VC程序每次都会去加载该dll,只做一次调用就卸载该dll么?如果是这样,那你怎么优化都没用,宿主的调用方式就有问题。
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/12/2 17:16:31
11楼: @souledge 用了全局的connection,确实快多了。
我写了个小demo,创建后loaddll,然后关闭程序freedll,发现占用内存才10m,但光一个数据库就上百m了,如果想把数据库放在内存中的话,应该怎么弄呢?
----------------------------------------------
-
作者:
男 gdsa (文稠紧) ★☆☆☆☆ -
盒子活跃会员
2015/4/14 18:31:55
12楼: 的确如上面所说,数据库池就是这样出来的
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行80.07813毫秒 RSS