Skip to content

Performance

Gwendal Roué edited this page Aug 7, 2019 · 68 revisions

Comparing the Performances of Swift SQLite libraries

Last updated August 6, 2019

Below are performance benchmarks made on for GRDB 4.2.0, FMDB 2.7.4, and SQLite.swift 0.12.2. They are compared to Core Data, Realm 3.17.3 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 10.2.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.06 0.04 0.05 0.41 ¹ ¹
Insert 0.10 0.03 0.20 0.11 ¹ ¹
Column names
Fetch 0.12 ¹ 0.18 0.82 ¹ ¹
Insert 0.13 ¹ 0.91 0.81 ¹ ¹
Records
Fetch 0.15 0.04 2.40 0.81 ¹ ¹
Insert 0.29 ¹ ¹ ¹ ¹ ¹
Codable Records
Fetch 0.27 ¹ ¹ ¹ ¹ ¹
Insert 0.27 ¹ ¹ ¹ ¹ ¹
Records with change tracking
Fetch 0.31 ¹ ¹ ¹ 0.29 0.12
Insert 0.32 ¹ ¹ ¹ 0.37 0.62

¹ 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
You can’t perform that action at this time.