Attention: il peut y avoir des inexactitudes ci-dessous. J'ai appris beaucoup de choses au fur et à mesure, alors prenez-le avec une pincée de sel. C'est assez long, mais vous pouvez simplement lire les paramètres avec lesquels nous jouions, puis passer à la conclusion à la fin.
Il existe un certain nombre de couches où vous pouvez vous soucier des performances d'écriture SQLite:
Nous avons examiné ceux mis en évidence en gras. Les paramètres particuliers étaient
- Cache d'écriture sur disque. Les disques modernes ont un cache RAM qui est utilisé pour optimiser les écritures de disque par rapport au disque en rotation. Lorsque cette option est activée, les données peuvent être écrites dans des blocs désordonnés, donc en cas de panne, vous pouvez vous retrouver avec un fichier partiellement écrit. Vérifiez le paramètre avec hdparm -W / dev / ... et réglez-le avec hdparm -W1 / dev / ... (pour l'activer et -W0 pour le désactiver).
- barrière = (0 | 1). Beaucoup de commentaires en ligne disant "si vous exécutez avec barrière = 0, alors la mise en cache d'écriture sur disque n'est pas activée". Vous pouvez trouver une discussion sur les obstacles à http://lwn.net/Articles/283161/
- data = (journal | ordonné | écriture différée). Consultez http://www.linuxtopia.org/HowToGuides/ext3JournalingFilesystem.html pour une description de ces options.
- commit = N. Indique à ext3 de synchroniser toutes les données et métadonnées toutes les N secondes (par défaut 5).
- Pragma SQLite synchrone = ON | DE. Lorsqu'il est activé, SQLite s'assurera qu'une transaction est «écrite sur le disque» avant de continuer. Si vous désactivez cette option, les autres paramètres sont essentiellement hors de propos.
- SQLite pragma cache_size. Contrôle la quantité de mémoire que SQLite utilisera pour son cache en mémoire. J'ai essayé deux tailles: une où la base de données entière tiendrait dans le cache, et une où le cache était la moitié de la taille maximale de la base de données.
En savoir plus sur les options ext3 dans la documentation ext3 .
J'ai effectué des tests de performances sur un certain nombre de combinaisons de ces paramètres. L'ID est un numéro de scénario, mentionné ci-dessous.
J'ai commencé par exécuter la configuration par défaut sur ma machine en tant que scénario 1. Le scénario 2 est ce que je suppose être le "plus sûr", puis j'ai essayé différentes combinaisons, le cas échéant / à l'invite. C'est probablement plus facile à comprendre avec la carte que j'ai fini par utiliser:
J'ai écrit un script de test qui a exécuté de nombreuses transactions, avec des insertions, des mises à jour et des suppressions, le tout sur des tables avec INTEGER uniquement, TEXT uniquement (avec la colonne id) ou mixtes. Je l'ai exécuté plusieurs fois sur chacune des configurations ci-dessus:
Les deux derniers scénarios sont # 6 et # 17, qui ont "pragma synchronous = off", si peu surprenant qu'ils étaient les plus rapides. Le prochain groupe de trois est # 7, # 11 et # 19. Ces trois sont surlignés en bleu sur la "carte de configuration" ci-dessus. Fondamentalement, la configuration est le cache d'écriture sur disque activé, la barrière = 0 et les données définies sur autre chose que «journal». Changer le commit entre 5 secondes (# 7) et 60 secondes (# 11) semble faire peu de différence. Sur ces tests, il ne semblait pas y avoir beaucoup de différence entre data = commandé et data = réécriture, ce qui m'a surpris.
Le test de mise à jour mixte est le pic du milieu. Il existe un groupe de scénarios qui sont plus clairement plus lents sur ce test. Ce sont tous ceux avec data = journal . Sinon, il n'y a pas grand-chose entre les autres scénarios.
J'ai eu un autre test de synchronisation, qui a fait un mélange plus hétérogène d'insertions, de mises à jour et de suppressions sur les différentes combinaisons de types. Cela a pris beaucoup plus de temps, c'est pourquoi je ne l'ai pas inclus dans l'intrigue ci-dessus:
Ici, vous pouvez voir que la configuration d'écriture différée (# 19) est un peu plus lente que celles commandées (# 7 et # 11). Je m'attendais à ce que l'écriture différée soit légèrement plus rapide, mais cela dépend peut-être de vos modèles d'écriture, ou peut-être que je n'ai pas encore assez lu sur ext3 :-)
Les différents scénarios étaient quelque peu représentatifs des opérations effectuées par notre application. Après avoir sélectionné une liste restreinte de scénarios, nous avons effectué des tests de synchronisation avec certaines de nos suites de tests automatisées. Ils étaient conformes aux résultats ci-dessus.
Conclusion
- Le paramètre commit semblait faire peu de différence, donc nous le laissons à 5 secondes.
- Nous allons avec le cache d'écriture sur disque, barrière = 0 et données = ordonnées . J'ai lu certaines choses en ligne qui pensaient que c'était une mauvaise configuration, et d'autres qui semblaient penser que cela devrait être la valeur par défaut dans de nombreuses situations. Je suppose que le plus important est que vous preniez une décision éclairée, sachant quels compromis vous faites.
- Nous n'allons pas utiliser le pragma synchrone dans SQLite.
- La définition du pragma SQLite cache_size pour que la base de données tienne en mémoire améliore les performances de certaines opérations, comme nous nous y attendions.
- La configuration ci-dessus signifie que nous prenons un peu plus de risques. Nous utiliserons l' API de sauvegarde SQLite pour minimiser le risque de défaillance du disque lors d'une écriture partielle: prendre un instantané toutes les N minutes et conserver le dernier M autour. J'ai testé cette API lors de l'exécution de tests de performances, et cela nous a donné confiance pour aller dans cette direction.
- Si nous voulions encore plus, nous pourrions envisager de nettoyer le noyau, mais nous avons suffisamment amélioré les choses sans y aller.
Merci à @Huygens pour divers conseils et conseils.