disqlite3_performance_fmain.pas

来自「DELPHI 访问SQLITE3 数据库的VCL控件」· PAS 代码 · 共 563 行 · 第 1/2 页

PAS
563
字号
      StartTime;

      Stmt := FDb.Prepare('SELECT Name, Random FROM t WHERE IdName = 5;');
      try
        if Stmt.Step = SQLITE_ROW then
          begin
            s := Stmt.Column_Str(0);
            r := Stmt.Column_Double(1); // Warning can be ignored - this is just a test!
            if Terminated then Exit;
          end
        else
          begin
            // Record not found.
          end;
      finally
        Stmt.Free;
      end;

      ShowTime('Locate a record based on an integer');

      //------------------------------------------------------------------------------
      // Locating 50 random records based on an integer
      //------------------------------------------------------------------------------

      { This is basically the same procedure as above, but wrapped in a for loop.
        The WHERE automatically uses the IdName's PRIMARY KEY index for very fast
        lookups.

        Notice that we prepare the statement ahead of the loop. This is critical to
        performance because preparing a statement is quite complicated and time-
        consuming (parsing the SQL creating the virtual machine, etc.). Reusing
        an already prepared statement can increase performance by 100% and more.

        See the next test for even faster lookups. }

      StartTime;

      Stmt := FDb.Prepare('SELECT Name, Random FROM t WHERE IdName=?;');
      try
        for i := 1 to 50 do
          begin
            { Bind the search value. }
            Stmt.Bind_Int(1, Random(FInsertCount));
            if Stmt.Step = SQLITE_ROW then
              begin
                s := Stmt.Column_Str(0);
                r := Stmt.Column_Double(1); // Warning can be ignored - this is just a test!
                if Terminated then Exit;
              end
            else
              begin
                // Record not found.
              end;
            Stmt.Reset;
          end;
      finally
        Stmt.Free;
      end;

      ShowTime('Locate 50 random values based on an integer');

      //------------------------------------------------------------------------------
      // Locate 5000 records based on an integer.
      //------------------------------------------------------------------------------

      { This is like the previous test but with a much increased the number of
        lookups. It uses the same loop, but wraps it in an exclusive transaction
        to avoid frequent database locks and unlocks between the individual locates.

        An exclusive transaction can speed up database operations which frequently
        change the database locking state. To lock the database, multi-user database
        engines like DISQLite3 usually set a flag in the database file. This
        requires disk write operations for each lookup and is therefore quite slow.
        The exclusive transaction saves us at least 5000 lock and unlock operation
        and usually speeds up this test by a factor of 2 and more. }

      StartTime;

      FDb.StartTransaction(ttExclusive);
      try
        Stmt := FDb.Prepare('SELECT Name, Random FROM t WHERE IdName = ?;');
        try
          for i := 1 to 5000 do
            begin
              Stmt.Bind_Int(1, Random(FInsertCount));
              if Stmt.Step = SQLITE_ROW then
                begin
                  s := Stmt.Column_Str(0);
                  r := Stmt.Column_Double(1); // Warning can be ignored - this is just a test!
                  if Terminated then Exit;
                end
              else
                begin
                  // Record not found.
                end;
              Stmt.Reset;
            end;
        finally
          Stmt.Free;
        end;
        FDb.Commit;
      except
        FDb.Rollback;
        raise;
      end;

      ShowTime('Locate 5000 random values based on an integer');

      //------------------------------------------------------------------------------
      // Rewriting records
      //------------------------------------------------------------------------------

      { Loop through the entire table to replace values. Make sure that you always
        use the RowID column in the UPDATE's WHERE clause: It is an auto-generated
        column which is always indexed and automatically guarantees best performance. }

      StartTime;

      StmtUpdate := FDb.Prepare('UPDATE t SET Name=?, Random=? WHERE RowID=?;');
      try
        Stmt := FDb.Prepare('SELECT Name, Random, RowID FROM t');
        try
          while Stmt.Step = SQLITE_ROW do
            begin
              StmtUpdate.Bind_Str(1, Stmt.Column_Str(0));
              StmtUpdate.Bind_Double(2, Stmt.Column_Double(1));
              StmtUpdate.Bind_Int(3, Stmt.Column_Int(2));
              StmtUpdate.Step;
              StmtUpdate.Reset;
              if Terminated then Exit;
            end;
        finally
          Stmt.Free;
        end;
      finally
        StmtUpdate.Free;
      end;

      ShowTime('Rewriting Records');

      //------------------------------------------------------------------------------
      // Creating an index on Name
      //------------------------------------------------------------------------------

      StartTime;

      { DISQLite3 creates an index by just executing a single SQL command. }
      FDb.Execute('CREATE INDEX First ON t (Name);');

      ShowTime('Creae an index on Name');

      //------------------------------------------------------------------------------
      // Locate a record based on a string
      //------------------------------------------------------------------------------

      { To locate a record with DISQLite3, simple add a WHERE statement to any
        SELECT. DISQLite3 will automatically choose from the available indexes to
        optimize the query and speed up performance. }

      StartTime;

      Stmt := FDb.Prepare('SELECT Name, Random FROM t WHERE Name = ''John'';');
      try
        if Stmt.Step = SQLITE_ROW then
          begin
            s := Stmt.Column_Str(0);
            r := Stmt.Column_Double(1); // Warning can be ignored - this is just a test!
            if Terminated then Exit;
          end
        else
          begin
            // Record not found.
          end
      finally
        Stmt.Free;
      end;

      ShowTime('Locating a record based on a string');

      //------------------------------------------------------------------------------
      // Filtering data
      //------------------------------------------------------------------------------

      { DISQLite3 filters data using the SQL WHERE clause. It can be followd by
        any expression, subquery, or user-defined function. The WHERE clause
        will automatically use existing indexes to speed up performance.
        Notice: There is no index defined for the "Random" column. }

      StartTime;

      Stmt := FDb.Prepare('SELECT Name, Random FROM t WHERE Random < 100;');
      try
        { Do whatever you need to do with the filtered. }
      finally
        Stmt.Free;
      end;

      ShowTime('Filtering data');

      //------------------------------------------------------------------------------
      // Start an exclusive transaction
      //------------------------------------------------------------------------------

      FDb.StartTransaction(ttExclusive);
      try
        // Do whatever you need to do with exclusive access to the database

        // When done modiying the database, commit your changes.
        FDb.Commit;
      except
        // If something went wrong, rollback changes to restore the previous database state.
        FDb.Rollback;
        raise;
      end;

      //------------------------------------------------------------------------------
      // Delete all records from table
      //------------------------------------------------------------------------------

      StartTime;

      FDb.Execute('DELETE FROM t;');

      ShowTime('Delete all records');

      //------------------------------------------------------------------------------

      WriteToLog('All tests finished');
    finally
      FDb.Free;
    end;

  except
    on e: ESQLite3 do
      if e.ErrorCode <> SQLITE_INTERRUPT then
        WriteToLog(e.Message);
    on e: Exception do
      WriteToLog(e.Message);
  end;
end;

//------------------------------------------------------------------------------

procedure TPerformanceThread.Interrupt;
begin
  Terminate;
  FDb.Interrupt;
end;

//------------------------------------------------------------------------------

procedure TPerformanceThread.ShowTime(const AMsg: AnsiString);
begin
  WriteToLog(AMsg + ':  ' + IntToStr(GetTickCount - FTickCount) + ' ms');
end;

//------------------------------------------------------------------------------

procedure TPerformanceThread.StartTime;
begin
  FTickCount := GetTickCount;
end;

//------------------------------------------------------------------------------

procedure TPerformanceThread.WriteToLog(const s: AnsiString = '');
begin
  FLogMessage := s;
  Synchronize(DoWriteToLog);
end;

//------------------------------------------------------------------------------

procedure TPerformanceThread.DoWriteToLog;
begin
  FLog.Add(FLogMessage);
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?