It is very common for us to use SQLite within our Xamarin apps, mainly with an async ORM package which standardises how we access the raw data from our databases. But for a fully functional app we need to select subsets of the data, join records and transform fields through to properties of our models and view-models. As developers we do this in various ways, dependent on our requirement and our experiences.
In this presentation you will see performance statistics on various methods across simulators, emulators, iOS and Android devices, including the user of reflection, multi-threading, AutoMapper and some consequence of generic ("Type T") programming. In addition Kym will walk through how to get update performance through transactional SQLite processing.
2. INTRODUCTION
• Purpose:
• How to get the best performance out of database reads for a client using
ZTE Blades.
• What is the overhead of reflection?
• What is the overhead of Automapper?
• How realistic are simulators and emulators with regards to SQLite
performance?
• Test environment:
• Standard iOS simulator (iPhone 7 running iOS 11)
• Genymotion Android emulator (Google Nexus 5 API23)
• (running on Mac 3.1Ghz i7, dual core, 16Gb memory)
• Iphone 6, ios 11, dual core, 1.4 Ghz
3. SQLITE IMPLEMENTATION (MY PREFERRED
IMPLEMENTATION)
• Nuget plugin: Sqlite.Net.async-PCL
• Asynchronous ORM tool (Object Relational Mapping).
• Implemented within a singleton behind an interface (“IDataService”):
• Singleton implemented using the Unity IoC container.
• Using an interface gives me flexibility to
• change in the future, and
• optimise independent of business logic.
• Three tier architecture:
• Persistence tier: everything behind the IDataServices interface (presentation
main focus).
• Business logic tier: models etc. (overhead of AutoMapper focuses
here).
• User Interface tier: Views and ViewModels.
4. DATA
• 1000 ActivityEvent DTO
records. (e.g. Bingo on
8/10/2017),
• Each with an embedded
activity type, location and
venue DTO.
• With a many-to-many list
of personnel who will
conduct the event.
• Total of about 5300
reads.
5. TESTS
10 tests run against the 4 environments:
A. Write speed.
B. Populate foreign key records using reflection.
C. No reflection.
D. Using 4 concurrent threads.
E. User Automapper to populate Model records from DTOs.
F. User Automapper with concurrent threads.
G. Assign fields directly rather than Automapper.
H. Assign fields with concurrent threads.
I. Direct ORM call records = await db.GetAllAsync<T>()
J. Query string call records = await db.QueryAsync<T>(“Select * from
table {0}”,name)
6. RESULTS
Pogram A Program B Program C Program D Program E Program F Program G Program H Program I Program J
Writes Reflection No reflection
Concurrent
threads
Automapper
Automapper
/ concurrent
No
Automapper
No
Automapper /
concurrent
direct query
iOS
rec/se
c 60 270 597 605 2,232 2,132 84,968 86,339 569 578
second
s 39.003 19.861 8.966 8.848 2.398 2.510 0.063 0.062 2.110 2.077
records 2330 5353 5353 5353 5353 5353 5353 5353 1200 1200
iOS Simulator rec/sec 291 625 604 2,949 2,919 24,697 22,137
second
s 8.000 1.599 1.657 0.339 0.343 0.040 0.045
records 2330 1000 1000 1000 1000 1000 1000
Android
rec/se
c 18 7 19 24 1,687 1,965 17,529 16,932 63 63
second
s 126.486 146.479 51.807 40.918 3.172 2.725 0.305 0.316 16.069 15.944
records 2330 5353 5353 5353 5353 5353 5353 5353 1010 1010
Android
Emulator rec/sec
78 159 2,560 3,231 4,311 3,595
second
s 12.890 6.288 0.391 0.309 0.232 0.278
records 1000 1000 1000 1000 1000 1000
7. SUMMARY
iOS Automapper overhead: 2.34
seconds per 1000
records 20.5%
Overhead on whole read
process
Reflection overhead: 10.89
seconds per 1000
records 55% Improvement
Concurrent processing
benefit: 0.12
seconds per 1000
records 1% Improvement
iOS Simulator Automapper overhead: 0.30
seconds per 1000
records 15.4%
Overhead on whole read
process
Concurrent processing
benefit: -0.06
seconds per 1000
records -4% Improvement
Android Automapper overhead: 2.87
seconds per 1000
records 5.2%
Overhead on whole read
process
Reflection overhead: 94.67
seconds per 1000
records 65% Improvement
Concurrent processing
benefit: 10.89
seconds per 1000
records 21% Improvement
Android
Emulator Automapper overhead: 0.16
seconds per 1000
records 1.1%
Overhead on whole read
process
Concurrent processing
benefit: 6.53
seconds per 1000
records 48% Improvement
8. MY CONCLUSIONS
1. Don’t use reflection.
2. Automapper has a significant overhead.
3. Concurrent processing has significant benefits on Android ZTE
devices …
4. Android ZTE very much slower than the iPhone (although we rarely
get a choice about device deployment)
5. The emulators and simulators a reasonable representation of devices
– relative to themselves. (i.e. a 10% performance improvement on an
emulator can expect a 10 improvement on a device)
6. There is no difference between generic ORM calls and ORM query
string calls.