Skip to content

Performance

Gwendal Roué edited this page May 2, 2020 · 83 revisions

Comparing the Performances of Swift SQLite libraries

Last updated May 2, 2020

Below are performance benchmarks made on for GRDB 5.0.0-beta, FMDB 2.7.5, and SQLite.swift 0.12.2. They are compared to Core Data, Realm 4.4.0 and the raw use of the SQLite C API from Swift.

This report was generated on a MacBook Pro (15-inch, Late 2016), with Xcode 11.4.1, by running the following command:

make test_performance | Tests/parsePerformanceTests.rb | Tests/generatePerformanceReport.rb

All tests use the default settings of each library. For each library, we:

  • Build and consume database rows with raw SQL and column indexes (aiming at the best performance)
  • Build and consume database rows with column names (sacrificing performance for maintainability)
  • Build and consume records values to and from database rows (aiming at the shortest code from database to records)
  • Build and consume records values to and from database rows, with help from the Codable standard protocol
  • Build and consume records values to and from database rows, with change tracking (records know if they have unsaved changes)

As a bottom line, the raw SQLite C API is used as efficiently as possible, without any error checking.

GRDB Raw SQLite FMDB SQLite.swift Core Data Realm
Column indexes
Fetch 0.09 0.06 0.06 0.55 ¹ ¹
Insert 0.10 0.02 0.16 0.12 ¹ ¹
Column names
Fetch 0.16 ¹ 0.23 0.88 ¹ ¹
Insert 0.13 ¹ 1.02 0.86 ¹ ¹
Records
Fetch 0.17 0.06 2.86 0.85 ¹ ¹
Insert 0.27 ¹ ¹ ¹ ¹ ¹
Codable Records
Fetch 0.32 ¹ ¹ ¹ ¹ ¹
Insert 0.25 ¹ ¹ ¹ ¹ ¹
Records with change tracking
Fetch 0.41 ¹ ¹ ¹ 0.34 0.16
Insert 0.32 ¹ ¹ ¹ 0.39 0.58

¹ Not applicable

  • Column indexes:

    • Fetch (source)

      This test fetches 100000 rows of 10 ints and extracts each int given its position in the row.

      It uses FMDB's -[FMResultSet longForColumnIndex:], GRDB's Row.value(atIndex:), and the low-level SQL API of SQLite.swift.

    • Insert (source)

      This test inserts 20000 rows of 10 ints, by setting query arguments given their position.

      It uses FMDB's -[FMDatabase executeUpdate:withArgumentsInArray:] with statement caching, GRDB's UpdateStatement.execute(arguments:Array), and the low-level SQL API of SQLite.swift.

  • Column names:

    • Fetch (source)

      This test fetches 100000 rows of 10 ints and extracts each int given its column name.

      It uses FMDB's -[FMResultSet longForColumn:], GRDB's Row.value(named:), and the high-level query builder of SQLite.swift.

    • Insert (source)

      This test inserts 20000 rows of 10 ints, by setting query arguments given their argument name.

      It uses FMDB's -[FMDatabase executeUpdate:withParameterDictionary:] with statement caching, GRDB's UpdateStatement.execute(arguments:Dictionary), and the high-level query builder of SQLite.swift.

  • Records:

    • Fetch (source)

      This test fetches an array of 100000 record objects initiated from rows of 10 ints.

      It builds records from FMDB's -[FMResultSet resultDictionary], GRDB's built-in FetchableRecord protocol, and the values returned by the high-level query builder of SQLite.swift.

    • Insert (source)

      This tests inserts 20000 records with the persistence method provided by GRDB's PersistableRecord protocol.

  • Codable Records:

  • Records with change tracking:

    • Fetch (source)

      This test fetches an array of 100000 record objects initiated from rows of 10 ints.

      It builds records from FMDB's -[FMResultSet resultDictionary], GRDB's built-in Record class.

    • Insert (source)

      This tests inserts 20000 records with the persistence method provided by GRDB's Record class.

Clone this wiki locally