Pour une fois, il s’agit de parler de ce que l’on ne montre pas toujours au public : «l’envers du décor», soit le backend base de données et la synchronisation avec l’application iPhone.
Le but de la session est de présenter notre expérience dans le contexte suivant :
Base de données locale Sqlite
Base de données serveur MySql
Synchronisation des données application - serveur
Présentation de l’application
Présentation de l’administration des données (écrans de maintenance des données intégrés à Joomla)
Présentation de l’approche et du code, productivité de développement pour le backend web
Sqlite sans CoreData
Echange des données en JSON
Procédures stockées et vues MySql
Discussion concernant les techniques possibles et la productivité
7. 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
8. Application mobile
Outil d’affichage de données
Fonctionne également hors ligne
Structure et design simple
Synchronisation des données
- robuste
- performante
14. Situation «typique»
Un client demande «une petite application
mobile multi-plateformes»
➡ aspect visuel et fonctionnel
➡ mais aussi développement important :
- back-end Web
- synchronisation
16. Options
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...)
18. Contexte: application iOS
Projet d’exemple Audio Guide
Modèle relationnel
Correspond au type de modèle du back-end
SQLite (sans Core Data)
Optimisation du SQL et des paramètres db
19. 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
25. Options d’accès à SQLite
•
Utilisation de Core Data
•
Utilisation directe de la libraire SQLite native
➡
Fonctions C
26. Options d’accès à SQLite
•
Utilisation de Core Data
•
Utilisation directe de la libraire SQLite native
➡
•
Fonctions C
Wrapper ou framework existant
➡
FMDB
27. Options d’accès à SQLite
•
Utilisation de Core Data
•
Utilisation directe de la libraire SQLite native
➡
•
Wrapper ou framework existant
➡
•
Fonctions C
FMDB
Wrapper «maison»
28. Options d’accès à SQLite
•
Utilisation de Core Data
•
Utilisation directe de la libraire SQLite native
➡
•
Wrapper ou framework existant
➡
•
Fonctions C
FMDB
Wrapper «maison»
-
raison historique, plaisir d’explorer
mainmise sur le code (tests)
46. Scénarios d’évolution des données
•
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)
47. Contexte
Projet 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é
48. Approches
•
•
•
•
Option 1 : «naïve» (la plus simple)
Option 2 : «typique SQLite» (transaction)
Option 3 : «insertion en masse»
Option 4 : «insertion en masse» + transaction
49. Contexte
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
50. Option 1
Insertion ligne par ligne
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
51. Option 1
Insertion ligne par ligne
insertions /
sec
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
52. Option 1
Insertion ligne par ligne
insertions /
sec
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
Trop lent !
53. Option 2
Insertion ligne par ligne…
dans une transaction
BEGIN TRANSACTION
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
COMMIT (or rollback)
54. Option 2
Insertion ligne par ligne…
dans une transaction
BEGIN TRANSACTION
insertions /
sec
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
COMMIT (or rollback)
55. Option 2
Insertion ligne par ligne…
dans une transaction
BEGIN TRANSACTION
insertions /
sec
FOR EACH ROW
EXEC:INSERT INTO TBL
(c1,c2...) SELECT 123,
‘abc’,...
COMMIT (or rollback)
2.5x plus rapide !
56. Option 3
Insertion de plusieurs lignes en
une commande insert
EXEC:
INSERT
VALUES
(123,
,(345,
,(678,
INTO TBL (c1,c2)
‘Sqlite’)
‘Soft’)
‘Shake’);
57. Option 3
Insertion de plusieurs lignes en
une commande insert
SQLite ne connait pas insert many values !
(dépend des versions de SQLite…)
EXEC:
INSERT
VALUES
(123,
,(345,
,(678,
INTO TBL (c1,c2)
‘Sqlite’)
‘Soft’)
‘Shake’);
58. Option 3 - syntaxe SQLite
Insertion de plusieurs lignes en
une commande insert
EXEC:
INSERT INTO TBL (c1,c2)
SELECT 123, ‘Sqlite’
UNION SELECT 345, ‘Soft’
UNION SELECT 678, ‘Shake’;
59. Option 3 - syntaxe SQLite
Insertion de plusieurs lignes en
une commande insert
Limite SQLite :
au maximum 500 union select !
EXEC:
INSERT INTO TBL (c1,c2)
SELECT 123, ‘Sqlite’
UNION SELECT 345, ‘Soft’
UNION SELECT 678, ‘Shake’;
60. Option 3 - syntaxe SQLite
Insertion 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’;
61. Option 3 - syntaxe SQLite
Insertion par paquets de 500
lignes
Code un peu plus
complexe
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’;
62. Option 4
Insertion par paquets de 500
lignes…
dans une transaction
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)
63. Option 4
Insertion 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)
65. Comparaison des 4 options
insertions /
sec
Option 4 45x plus rapide que l’option 1
1500 insertions / seconde sur iPad 3
600 insertions / seconde sur iPhone 4
66. Option 4
Insertion par paquets de 500
lignes…
dans une transaction
Performance satisfaisante dans le contexte
Au prix d’un code un peu plus complexe
Optio
adopt n
ée !
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)
67. Insert et Update
•
•
Coder «if exists update else insert»
•
•
Long à développer, long à exécuter
Update forcément itératif avec SQLite (1 by 1)
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
Optio
adopt n
ée !
68. Insert et Replace
•
•
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
69. 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 ....
70. 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 ....
work
aroun
d
30% p
lus le !
nt.
71. Insert et Replace - commentaires
•
•
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
Optio
adopt n
ée !
72. Delete
•
Côté serveur
- «soft delete» (flag data inactive)
•
Côté application
- delete physique (à la fin de la synchronisation)
73. Réorganisation DB
•
•
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
74. Quand réorganiser ?
•
•
•
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»
75. Quand réorganiser ?
•
•
•
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»
vacuum est assez rapide
surtout s’il est effectué avant que la db soit totalement désorganisée
Important de le faire, «peu importe» quand !
76. 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
77. Pour conclure
•
•
SQLite est excellent et très performant !
•
Utiliser EXPLAIN pour analyser ce que fait SQLite
En définissant bien les indexes, pas de soucis de performance
du côté des select
82. Backend web - gestion des données
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
83. Gestion des données - nos choix
•
•
«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)
84. Core Data - iOS 7 - Sqlite
•
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