softshake apiness l'envers du décor

84
L’envers du décor 24 Octobre 2013

Upload: apinesssa

Post on 13-Apr-2017

312 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Softshake apiness l'envers du décor

L’envers du décor24 Octobre 2013

Page 2: Softshake apiness l'envers du décor

Apiness SA

Laurent Kohler & Nicolas Marfurt

www.apiness-software.ch

Page 3: Softshake apiness l'envers du décor

Le décor

Page 4: Softshake apiness l'envers du décor
Page 5: Softshake apiness l'envers du décor

Services Web

Echange de données

Page 6: Softshake apiness l'envers du décor

Services Web

Echange de données

Page 7: Softshake apiness l'envers du décor

Back-end Web

Gestion du contenu de l’application(data model «business»)• Multilingue• Multi-utilisateurs• Gestion des autorisations

- par fonction- sur la donnée

Web services de synchronisation

Page 8: Softshake apiness l'envers du décor

Application mobile

Outil d’affichage de données

Fonctionne également hors ligne

Structure et design simple

Synchronisation des données- robuste- performante

Page 9: Softshake apiness l'envers du décor
Page 10: Softshake apiness l'envers du décor
Page 11: Softshake apiness l'envers du décor

Effort de développement

Page 12: Softshake apiness l'envers du décor

Effort de développement

Page 13: Softshake apiness l'envers du décor

Effort de développement

Page 14: Softshake apiness l'envers du décor

Un client demande «une petite application mobile multi-plateformes»

➡ aspect visuel et fonctionnel

➡ mais aussi développement important :- back-end Web- synchronisation

Situation «typique»

Page 15: Softshake apiness l'envers du décor

L’envers du décor

Page 16: Softshake apiness l'envers du décor

Web server & Web services

Persistance données côté client mobile

- Modèle objet (Core Data)

- Modèle relationnel (SQLite natif)

- Autre (XML, JSON, plist...)

Options

Page 17: Softshake apiness l'envers du décor

Contexte: back-end

LAMP

CMS Joomla

Données «structurées», modèle relationnel (MySQL)

Projet d’exemple Audio Guide

Page 18: Softshake apiness l'envers du décor

Modèle relationnelCorrespond au type de modèle du back-end

SQLite (sans Core Data)Optimisation du SQL et des paramètres db

Contexte: application iOSProjet d’exemple Audio Guide

Page 19: Softshake apiness l'envers du décor

Modèle de données

Modèle «server» != modèle «app»Exemples :

• Serveur - Données multilingue - Gestion des autorisations

• Application - Une langue sélectionnée

Page 20: Softshake apiness l'envers du décor

Au travail !

Page 21: Softshake apiness l'envers du décor

iOS - Cocoa

Page 22: Softshake apiness l'envers du décor

Options d’accès à SQLite

Page 23: Softshake apiness l'envers du décor

Options d’accès à SQLite

• Utilisation de Core Data

Page 24: Softshake apiness l'envers du décor

Options d’accès à SQLite

• Utilisation de Core Data

Page 25: Softshake apiness l'envers du décor

Options d’accès à SQLite

• Utilisation de Core Data

• Utilisation directe de la libraire SQLite native➡ Fonctions C

Page 26: Softshake apiness l'envers du décor

Options d’accès à SQLite

• Utilisation de Core Data

• Utilisation directe de la libraire SQLite native➡ Fonctions C

• Wrapper ou framework existant➡ FMDB

Page 27: Softshake apiness l'envers du décor

Options d’accès à SQLite

• Utilisation de Core Data

• Utilisation directe de la libraire SQLite native➡ Fonctions C

• Wrapper «maison»

• Wrapper ou framework existant➡ FMDB

Page 28: Softshake apiness l'envers du décor

- raison historique, plaisir d’explorer- mainmise sur le code (tests)

Options d’accès à SQLite

• Utilisation de Core Data

• Utilisation directe de la libraire SQLite native➡ Fonctions C

• Wrapper «maison»

• Wrapper ou framework existant➡ FMDB

Page 29: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

Page 30: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

Page 31: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

MyProjectDatabaseController

Page 32: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

MyProjectDatabaseController

Page 33: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

MyClassResultSetMyProjectDatabaseController

Page 34: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

MyProjectDatabaseController MyClassResultSet

Page 35: Softshake apiness l'envers du décor

Architecture

APSSQLite

SQLite

APSSQLiteDatabase APSSQLiteResultSetAPSSQLiteRequest

APSSQLiteDatabaseController APSSQLiteObjectPersistingprotocol

APSSQLiteObjectCodingprotocol

MyProjectDatabaseController MyClassMyClassResultSet

Page 36: Softshake apiness l'envers du décor

Intégration

Contrôleur Modèle

MyViewController

MyClassResultSet

MyClass

APSSQLite

MyP

roje

ctDa

taba

seC

ontro

ller

Page 37: Softshake apiness l'envers du décor

Demo

Page 38: Softshake apiness l'envers du décor

Appel SQLite

- (BOOL)executeCUDRequest:(APSSQLiteRequest *)request error:(NSError *__autoreleasing *)error {! BOOL success = YES;

! sqlite3_stmt *statement; int rc = sqlite3_prepare(self.db, [request.query UTF8String], -1, &statement, NULL); ! if(rc == SQLITE_OK) { rc = sqlite3_step(statement); ! ! if(rc != SQLITE_DONE) { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! ! success = NO;! ! }! ! sqlite3_finalize(statement);! } else { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! success = NO;! } ! return success;}

APSSQLiteDatabase

Page 39: Softshake apiness l'envers du décor

Appel SQLite

- (BOOL)executeCUDRequest:(APSSQLiteRequest *)request error:(NSError *__autoreleasing *)error {! BOOL success = YES;

! sqlite3_stmt *statement; int rc = sqlite3_prepare(self.db, [request.query UTF8String], -1, &statement, NULL); ! if(rc == SQLITE_OK) { rc = sqlite3_step(statement); ! ! if(rc != SQLITE_DONE) { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! ! success = NO;! ! }! ! sqlite3_finalize(statement);! } else { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! success = NO;! } ! return success;}

APSSQLiteDatabase

- (BOOL)executeCUDRequest:(APSSQLiteRequest *)request error:(NSError *__autoreleasing *)error {! BOOL success = YES;

! sqlite3_stmt *statement; int rc = sqlite3_prepare(self.db, [request.query UTF8String], -1, &statement, NULL); ! if(rc == SQLITE_OK) { rc = sqlite3_step(statement); ! ! if(rc != SQLITE_DONE) { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! ! success = NO;! ! }! ! sqlite3_finalize(statement);! } else { *error = [[self class] errorWithCode:rc message:[NSString stringWithUTF8String:sqlite3_errmsg(self.db)]];! ! success = NO;! } ! return success;}

Page 40: Softshake apiness l'envers du décor

Exécution d’une requête

+ (TopicResultSet *)fetchAll { __block TopicResultSet *resultSet = nil; [[GuideDatabaseController sharedDatabaseController] performBlockAndWait:^(APSSQLiteDatabase *database) { NSString *query = @"SELECT * FROM audio_topic t WHERE t.isPublished = 1 ORDER BY t.sequence"; APSSQLiteRequest *request = [APSSQLiteRequest requestWithQuery:query]; request.resultClass = [TopicResultSet class]; NSError *error = nil; resultSet = [database executeFetchRequest:request error:&error]; // Handle error... }]; return resultSet;}

TopicResultSet : APSSQLiteResultSet

Page 41: Softshake apiness l'envers du décor

Exécution d’une requête

+ (TopicResultSet *)fetchAll { __block TopicResultSet *resultSet = nil; [[GuideDatabaseController sharedDatabaseController] performBlockAndWait:^(APSSQLiteDatabase *database) { NSString *query = @"SELECT * FROM audio_topic t WHERE t.isPublished = 1 ORDER BY t.sequence"; APSSQLiteRequest *request = [APSSQLiteRequest requestWithQuery:query]; request.resultClass = [TopicResultSet class]; NSError *error = nil; resultSet = [database executeFetchRequest:request error:&error]; // Handle error... }]; return resultSet;}

TopicResultSet : APSSQLiteResultSet

+ (TopicResultSet *)fetchAll { __block TopicResultSet *resultSet = nil; [[GuideDatabaseController sharedDatabaseController] performBlockAndWait:^(APSSQLiteDatabase *database) { NSString *query = @"SELECT * FROM audio_topic t WHERE t.isPublished = 1 ORDER BY t.sequence"; APSSQLiteRequest *request = [APSSQLiteRequest requestWithQuery:query]; request.resultClass = [TopicResultSet class]; NSError *error = nil; resultSet = [database executeFetchRequest:request error:&error]; // Handle error... }]; return resultSet;}

Page 42: Softshake apiness l'envers du décor

Affichage des données

- (void)viewDidLoad { [super viewDidLoad]; self.topicResultSet = [TopicResultSet fetchAll];}

MyViewController : UITableViewController

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.topicResultSet count];}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TopicTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TopicListViewControllerTopicCell]; NSDictionary *topic = self.topicResultSet[indexPath.row]; cell.textLabel.text = topic[TopicColumnTitle]; cell.detailTextLabel.text = topic[TopicColumnDescription]; return cell;}

@interface TopicListViewController ()

@property (strong, nonatomic) TopicResultSet *topicResultSet;

@end

Page 43: Softshake apiness l'envers du décor

Affichage des données

- (void)viewDidLoad { [super viewDidLoad]; self.topicResultSet = [TopicResultSet fetchAll];}

MyViewController : UITableViewController

@interface TopicListViewController ()

@property (strong, nonatomic) TopicResultSet *topicResultSet;

@end

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.topicResultSet count];}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TopicTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TopicListViewControllerTopicCell]; return cell;}

Page 44: Softshake apiness l'envers du décor

Affichage des données

- (void)viewDidLoad { [super viewDidLoad]; self.topicResultSet = [TopicResultSet fetchAll];}

MyViewController : UITableViewController

@interface TopicListViewController ()

@property (strong, nonatomic) TopicResultSet *topicResultSet;

@end

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.topicResultSet count];}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TopicTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TopicListViewControllerTopicCell]; return cell;}

Topic *topic = [self.topicResultSet topicForRowAtIndex:indexPath.row]; cell.textLabel.text = topic.title; cell.detailTextLabel.text = topic.topicDescription;

Page 45: Softshake apiness l'envers du décor

Base de données

Page 46: Softshake apiness l'envers du décor

• Mises à jour fréquentes mais en petit volume (news)

➡ Intégralité des données pas nécessaire

• Mises à jour en masse (catalogue produit)

• Installation en masse, mises à jour de petit volume (audio guide)

Scénarios d’évolution des données

Page 47: Softshake apiness l'envers du décor

ContexteProjet d’exemple Audio Guide

• Installation de contenu type «audio guide musée»

- Texte, images, audio

- Création par volume de 100 à 1000 éléments environ

- Mise à jour sporadique et en petite quantité

Page 48: Softshake apiness l'envers du décor

Approches

• Option 1 : «naïve» (la plus simple)

• Option 2 : «typique SQLite» (transaction)

• Option 3 : «insertion en masse»

• Option 4 : «insertion en masse» + transaction

Page 49: Softshake apiness l'envers du décor

2 tables relativement petites

- table parent : 12 colonnes (int, float, varchar)

- table détail : 7 colonnes (int, varchar), foreign key parent

Mesure

- nombre d’insertions par seconde

- données de référence : 1000 parents et 2000 détails

Contexte

Page 50: Softshake apiness l'envers du décor

Insertion ligne par ligne

Option 1

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

Page 51: Softshake apiness l'envers du décor

Insertion ligne par ligne

Option 1

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

insertions /sec

Page 52: Softshake apiness l'envers du décor

Insertion ligne par ligne

Option 1

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

insertions /sec

Trop lent !

Page 53: Softshake apiness l'envers du décor

Option 2

BEGIN TRANSACTION

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

COMMIT (or rollback)

Insertion ligne par ligne…

dans une transaction

Page 54: Softshake apiness l'envers du décor

Option 2

BEGIN TRANSACTION

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

COMMIT (or rollback)

Insertion ligne par ligne…

dans une transaction

insertions /sec

Page 55: Softshake apiness l'envers du décor

Option 2

BEGIN TRANSACTION

FOR EACH ROW

EXEC:INSERT INTO TBL (c1,c2...) SELECT 123, ‘abc’,...

COMMIT (or rollback)

Insertion ligne par ligne…

dans une transaction

2.5x plus rapide !

insertions /sec

Page 56: Softshake apiness l'envers du décor

Option 3

EXEC:INSERT INTO TBL (c1,c2) VALUES (123, ‘Sqlite’),(345, ‘Soft’),(678, ‘Shake’);

Insertion de plusieurs lignes en une commande insert

Page 57: Softshake apiness l'envers du décor

Option 3

EXEC:INSERT INTO TBL (c1,c2) VALUES (123, ‘Sqlite’),(345, ‘Soft’),(678, ‘Shake’);

SQLite ne connait pas insert many values !(dépend des versions de SQLite…)

Insertion de plusieurs lignes en une commande insert

Page 58: Softshake apiness l'envers du décor

Option 3 - syntaxe SQLite

EXEC:INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’UNION SELECT 345, ‘Soft’UNION SELECT 678, ‘Shake’;

Insertion de plusieurs lignes en une commande insert

Page 59: Softshake apiness l'envers du décor

Option 3 - syntaxe SQLite

EXEC:INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’UNION SELECT 345, ‘Soft’UNION SELECT 678, ‘Shake’;

Limite SQLite :

au maximum 500 union select !

Insertion de plusieurs lignes en une commande insert

Page 60: Softshake apiness l'envers du décor

Option 3 - syntaxe SQLiteInsertion par paquets de 500 lignes

FOR EACH ROW BUILD INSERT STATEMENT WHEN «ENOUGH» EXEC: INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’ UNION SELECT 345, ‘Soft’ UNION SELECT 678, ‘Shake’;

Page 61: Softshake apiness l'envers du décor

Option 3 - syntaxe SQLiteInsertion par paquets de 500 lignes

FOR EACH ROW BUILD INSERT STATEMENT WHEN «ENOUGH» EXEC: INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’ UNION SELECT 345, ‘Soft’ UNION SELECT 678, ‘Shake’;

Code un peu pluscomplexe

Page 62: Softshake apiness l'envers du décor

Option 4Insertion par paquets de 500 lignes…dans une transactionBEGIN TRANSACTION

FOR EACH ROW BUILD INSERT STATEMENT WHEN «ENOUGH» EXEC: INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’ UNION SELECT 345, ‘Soft’ UNION SELECT 678, ‘Shake’;

COMMIT (or rollback)

Page 63: Softshake apiness l'envers du décor

Option 4Insertion par paquets de 500 lignes…dans une transaction

Insertion «rapide»de nombreuses lignes

BEGIN TRANSACTION

FOR EACH ROW BUILD INSERT STATEMENT WHEN «ENOUGH» EXEC: INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’ UNION SELECT 345, ‘Soft’ UNION SELECT 678, ‘Shake’;

COMMIT (or rollback)

Page 64: Softshake apiness l'envers du décor

Comparaison des 4 options

insertions /sec

Page 65: Softshake apiness l'envers du décor

Comparaison des 4 options

Option 4 45x plus rapide que l’option 11500 insertions / seconde sur iPad 3600 insertions / seconde sur iPhone 4

insertions /sec

Page 66: Softshake apiness l'envers du décor

Option 4Insertion par paquets de 500 lignes…dans une transaction

Performance satisfaisante dans le contexteAu prix d’un code un peu plus complexe

BEGIN TRANSACTION

FOR EACH ROW BUILD INSERT STATEMENT WHEN «ENOUGH» EXEC: INSERT INTO TBL (c1,c2) SELECT 123, ‘Sqlite’ UNION SELECT 345, ‘Soft’ UNION SELECT 678, ‘Shake’;

COMMIT (or rollback)

Optionadoptée !

Page 67: Softshake apiness l'envers du décor

• Coder «if exists update else insert»

• Long à développer, long à exécuter

• Update forcément itératif avec SQLite (1 by 1)

Insert et Update

• Approche SQLite efficace : INSERT OR REPLACE INTO...

➡ Si validation intégrité référentielle (foreign key)

Différer le contrôle au moment du commit :PRAGMA defer_foreign_keys = ON

Optionadoptée !

Page 68: Softshake apiness l'envers du décor

• Parfait pour des données provenant à 100% du serveur

• Attention si certaines colonnes sont maintenues localement !

• Le «insert or replace» modifie toutes les colonnes

➡ Option possible :

Utiliser un sub-select pour obtenir la valeur locale

Insert et Replace

Page 69: Softshake apiness l'envers du décor

Insert et Replace - exemple

EXEC:INSERT INTO news (newsId, newsTitle,newsDesc, hasBeenRead) SELECT 123,‘SoftShake 2013’,’24 et 25 octobre 2013’,(SELECT hasBeenRead FROM news WHERE newsId = 123)UNION SELECT ....

Page 70: Softshake apiness l'envers du décor

Insert et Replace - exemple

EXEC:INSERT INTO news (newsId, newsTitle,newsDesc, hasBeenRead) SELECT 123,‘SoftShake 2013’,’24 et 25 octobre 2013’,(SELECT hasBeenRead FROM news WHERE newsId = 123)UNION SELECT ....

workaround !30% plus lent.

Page 71: Softshake apiness l'envers du décor

• Lorsque certaines colonnes sont maintenues localement

• Data model :

- une table pour les données «serveur»

- une table pour les données «locale»

- une view pour accéder aux 2 facilement

• Pas de perte de performance

• Approche robuste

Insert et Replace - commentaires

Optionadoptée !

Page 72: Softshake apiness l'envers du décor

• Côté serveur

- «soft delete» (flag data inactive)

• Côté application

- delete physique (à la fin de la synchronisation)

Delete

Page 73: Softshake apiness l'envers du décor

• SQLite est comparable aux autres base de données

• Après de nombreux insert/update/delete, besoin de :

- Récupérer l’espace avec : VACUUM

Réorganisation DB

Page 74: Softshake apiness l'envers du décor

• A l’ancienne; «une fois par semaine» ?

• Souvent; après chaque synchro ?

• Lorsque jugé nécessaire ?

- Evaluer les pages vides avec PRAGMA freelist_count

- Si «nombreuses» pages inutilisées : effectuer le «vacuum»

Quand réorganiser ?

Page 75: Softshake apiness l'envers du décor

• A l’ancienne; «une fois par semaine» ?

• Souvent; après chaque synchro ?

• Lorsque jugé nécessaire ?

- Evaluer les pages vides avec PRAGMA freelist_count

- Si «nombreuses» pages inutilisées : effectuer le «vacuum»

Quand réorganiser ?

vacuum est assez rapidesurtout s’il est effectué avant que la db soit totalement désorganisée

Important de le faire, «peu importe» quand !

Page 76: Softshake apiness l'envers du décor

Options SQLite• Journal mode

• Mode «delete» par défaut

• Attention au mode Write Ahead Log (WAL)

• Meilleure concurrence d’accès

• Meilleure performance «maintenant»...

- Car une partie du travail différée à plus tard !

- Sur device mobile, comportement potentiellement ennuyeux

Page 77: Softshake apiness l'envers du décor

• SQLite est excellent et très performant !

• En définissant bien les indexes, pas de soucis de performance du côté des select

• Utiliser EXPLAIN pour analyser ce que fait SQLite

Pour conclure

Page 78: Softshake apiness l'envers du décor

Merci à vous tous pour votre attention !

Page 79: Softshake apiness l'envers du décor

NoSQL

?

Cor

e Da

ta ?

SQLi

te ?

Back

-end

W

eb?

Discussion

Page 80: Softshake apiness l'envers du décor

BACKUP SLIDES

Page 81: Softshake apiness l'envers du décor

Backend web - gestion des données

Page 82: Softshake apiness l'envers du décor

Outils existants (connus)

• Contraintes par rapport au data model

• (Très) rapide pour des fonctions simples

• Risque d’atteindre une impasse

Développement «sur mesure»

• trop long, trop coûteux

Backend web - gestion des données

Page 83: Softshake apiness l'envers du décor

• «middle-tier» commun qui génère le html en fonction de paramètres et accès aux données par procédures stockées

• Code PHP stable, on génère/écrit seulement le sql

• Rapide

• Optimisation des stored procedures toujours possible

• Outil «maison» : JEdit

• Développement par Apiness (Marc Perroulaz, L.Kohler)

Gestion des données - nos choix

Page 84: Softshake apiness l'envers du décor

• Version SQLite

• - iOS 6: version 3.7.13

• - iOS 7.0: version 3.7.13

• Options Core Data

• Utilisation du mode WAL par défaut depuis iOS 7

• Possibilité de passer des options SQLite à Core Data, entre autre le mode de journalisation:

• @{ NSSQLitePragmasOption : @{@"journal_mode" : @"DELETE"} }

• Trace Core Data (iOS 7 / sans analyse)

• - pragma journal_mode=wal

• - pragma cache_size=200

• - pragma page_count

• - pragma freelist_count

Core Data - iOS 7 - Sqlite