导致mdb数据库超过2GB限制的ADO查询

时间:2016-02-02 10:28:42

标签: delphi ms-access jet

我正在使用下面的Delphi代码用utf = 8格式的大型csv文件替换Access数据库中的表。在我开始之前,数据库是946MB。一切都好,直到我的桌子达到一定的大小然后我得到一个错误。发生这种情况时,数据库已超过2GB。我猜测也许Jet引擎正在创建一个导致溢出的内部副本 - 是否有任何方法可以阻止这种情况,或者有人可能建议使用不同的方法导入我的数据而避免它?

function TCSVDatabase.ADOFromCSV(ConStr: string): Boolean;
var
  J, K: Integer;
  S: string;
  SN, DN: string;
  DefDir: string;
  DestDir: string;
  TN: TStringList;
begin
  BeginUpdate;
  Result := False;
  DoProgress(0, 'Initializing...');
  DN := ADOSetConnectionString(ConStr);
  if FileExists(DN) then
  begin
    DestDir := ExtractFilePath(DN);
    TN := TStringList.Create;
    Result := True;
    try
      DefDir := FDefaultPath;
      FDefaultPath := DestDir;
      TN.Assign(ADOGetTableNames);
      for K := 0 to TN.Count - 1 do
      begin
        SN := DestDir + TN[K] + '.csv';
        if FileExists(SN) then
        begin
          DoProgress(0, 'Opening "' + TN[K] + '"...');
          FADOTable.Close;
          while FADOTable.Active do;
          FADOTable.Connection := FADOConnection;
          FADOTable.TableName := TN[K];
          FADOTable.Open;
          if FADOTable.Active then
          begin
            Result := True;
            ADOGetFieldNames;
            FADOQuery.Connection := FADOConnection;
            FADOQuery.Recordset := FADOTable.Recordset;
            FADOQuery.Open;
            DoProgress(0, 'Emptying "' + TN[K] + '"...');
            FADOQuery.SQL.Text := 'DELETE * FROM [' + TN[K] + ']';
            FADOQuery.ExecSQL;
            S := ExtractFilePath(SN);
            SetLength(S, Length(S) - 1);
            try
              DoProgress(0, 'Filling "' + TN[K] + '"...');
              FADOQuery.SQL.Text := 'INSERT INTO [' + TN[K] +
                '] SELECT * FROM [' + ExtractFileName(SN) + '] IN "' + S +
                '" "Text;HDR=YES;FMT=Delimited(,);CharacterSet=65001;"';
              FADOQuery.ExecSQL;
            except
              FADOQuery.Connection := nil;
              FADOQuery.Close;
              DoProgress(0, 'SQL error in "' + TN[K] + '"');
{$IFDEF VCL}
              ShowMessage('SQL error in "' + TN[K]);
{$ENDIF}
              Result := False;
              Exit;
            end;
            FADOQuery.Connection := nil;
            FADOQuery.Close;
            for J := 0 to FTemp.Count - 1 do
            begin
              if (FTemp.Codes[J] in [FT_MEMO, FT_WIDEMEMO]) then
              begin
                FADOTable.First;
                while (not FADOTable.EOF) do
                begin
                  S := FADOTable.Fields[J].AsString;
                  if (Pos('_\', S) <> 0) then
                  begin
                    S := StringReplace(S, '_\r\n_', #13#10, [rfReplaceAll]);
                    S := StringReplace(S, '_\r_', #13, [rfReplaceAll]);
                    S := StringReplace(S, '_\n_', #10, [rfReplaceAll]);
                    FADOTable.Edit;
                    FADOTable.Fields[J].AsString := S;
                    FADOTable.Post;
                  end;
                  FADOTable.Next;
                end;
              end;
            end;
          end;
        end;
        DoProgress(0, '');
      end;
    finally
      FADOTable.Close;
      if Result then
      begin
        DoProgress(0, 'Compacting...');
        CompactDatabase(DN, FADOConnection);
      end;
      FDefaultPath := DefDir;
      TN.Free;
    end;
  end;
  DoProgress(0, '');
  EndUpdate;
end;

2 个答案:

答案 0 :(得分:3)

我的解决方案是清除表并在两个单独的过程中重新填充它们,其间有一个CompactDatabase。感谢大家的建议,我希望我的解决方案可以帮助别人: - )

PS谢谢Sam我在测试完修补程序后看到了你的答案,基本上就是你的建议!

function TCSVDatabase.ADOFromCSV(ConStr: string): Boolean;
var
  Err: Cardinal;
  J, K: Integer;
  S: string;
  SN, DN: string;
  DefDir: string;
  DestDir: string;
  TN: TStringList;
begin
  BeginUpdate;
  Result := False;
  DoProgress(0, 'Initializing...');
  DN := ADOSetConnectionString(ConStr);
  if FileExists(DN) then
  begin
    DestDir := ExtractFilePath(DN);
    TN := TStringList.Create;
    Result := True;
    try
      DefDir := FDefaultPath;
      FDefaultPath := DestDir;
      TN.Assign(ADOGetTableNames);
      for K := 0 to TN.Count - 1 do
      begin
        SN := DestDir + TN[K] + '.csv';
        if FileExists(SN) then
        begin
          DoProgress(0, 'Emptying "' + TN[K] + '"...');
          FADOTable.Close;
          while FADOTable.Active do;
          FADOTable.Connection := FADOConnection;
          FADOTable.TableName := TN[K];
          FADOTable.Open;
          if FADOTable.Active then
          begin
            Result := True;
            ADOGetFieldNames;
            FADOQuery.Connection := FADOConnection;
            FADOQuery.Recordset := FADOTable.Recordset;
            FADOQuery.Open;
            FADOQuery.SQL.Text := 'DELETE * FROM [' + TN[K] + ']';
            FADOQuery.ExecSQL;
          end;
        end;
        DoProgress(0, '');
      end;
      DoProgress(0, 'Compacting...');
      CompactDatabase(DN, FADOConnection);
      DN := ADOSetConnectionString(ConStr);
      for K := 0 to TN.Count - 1 do
      begin
        SN := DestDir + TN[K] + '.csv';
        if FileExists(SN) then
        begin
          DoProgress(0, 'Opening "' + TN[K] + '"...');
          FADOTable.Close;
          while FADOTable.Active do;
          FADOTable.Connection := FADOConnection;
          FADOTable.TableName := TN[K];
          FADOTable.Open;
          if FADOTable.Active then
          begin
            Result := True;
            ADOGetFieldNames;
            FADOQuery.Connection := FADOConnection;
            FADOQuery.Recordset := FADOTable.Recordset;
            FADOQuery.Open;
            S := ExtractFilePath(SN);
            SetLength(S, Length(S) - 1);
            try
              DoProgress(0, 'Filling "' + TN[K] + '"...');
              FADOQuery.SQL.Text := 'INSERT INTO [' + TN[K] +
                '] SELECT * FROM [' + ExtractFileName(SN) + '] IN "' + S +
                '" "Text;HDR=YES;FMT=Delimited(,);CharacterSet=65001;"';
              FADOQuery.ExecSQL;
            except
              FADOQuery.Connection := nil;
              FADOQuery.Close;
              DoProgress(0, 'Error in "' + TN[K] + '"');
              ShowMessage('Error in "' + TN[K] + '"' );
              Result := False;
              Exit;
            end;
            FADOQuery.Connection := nil;
            FADOQuery.Close;
            for J := 0 to FTemp.Count - 1 do
            begin
              if (FTemp.Codes[J] in [FT_MEMO, FT_WIDEMEMO]) then
              begin
                FADOTable.First;
                while (not FADOTable.EOF) do
                begin
                  S := FADOTable.Fields[J].AsString;
                  if (Pos('_\', S) <> 0) then
                  begin
                    S := StringReplace(S, '_\r\n_', #13#10, [rfReplaceAll]);
                    S := StringReplace(S, '_\r_', #13, [rfReplaceAll]);
                    S := StringReplace(S, '_\n_', #10, [rfReplaceAll]);
                    FADOTable.Edit;
                    FADOTable.Fields[J].AsString := S;
                    FADOTable.Post;
                  end;
                  FADOTable.Next;
                end;
              end;
            end;
          end;
        end;
        DoProgress(0, '');
      end;
    finally
      FADOTable.Close;
      if Result then
      begin
        DoProgress(0, 'Compacting...');
        CompactDatabase(DN, FADOConnection);
      end;
      FDefaultPath := DefDir;
      TN.Free;
    end;
  end;
  DoProgress(0, '');
  EndUpdate;
end;

答案 1 :(得分:0)

您需要拆分数据库。来自Access 2007 specifications

  

访问数据库(.accdb)文件大小

     

2千兆字节,减去系统对象所需的空间

     

注意虽然单个数据库文件的最大大小为2GB,   您可以使用拆分数据库解决此限制。一个   前端数据库文件可以指向数千个后端数据库   文件,每个文件可能大到2GB。欲获得更多信息,   请参阅拆分Access数据库主题。

您还应该考虑转移到另一个关系数据库管理系统(RDBMS),如Oracle,SQL服务器,FireBird(您可以命名)