Leed : Pourquoi SQLite3 est un mauvais choix

Attention je ne dis pas qu’SQLite3 est un mauvais choix dans tous les cas

 

Mais plus je poursuis le développement de mon aggrégateur de flux RSS Leed, plus je me rend compte des lacunes de cette technologie dans mon cas.

 

J’avais initialement choisis Sqlite3 pour les raisons suivantes :

  • Léger
  • Facile à exporter/importer
  • Tiens en un seul fichier
  • Ne nécessite pas d’authentification
  • Ne nécessite pas de Serveur de gestion de base de données

 

Voila maintenant les raisons pour lesquelles j’ai décidé que Leed passerait définitivement et uniquement en MySQL sous peu :

  1. Les fichiers SQLite3 prennent du poids à une vitesse hallucinante
  2. SQLite3 demande des pré requis serveur que certains hébergeurs ne parviennent pas à offrir (ou du moins il faut bidouiller).
  3. A partir d’une certaine quantité de données, SQLite réagit au final plus lentement que de plus gros poissons comme MySQL
  4. Au delà de 6/7 Mo, le fichier est verrouillé en écriture par la plupart des config PHP

 

Le point 4 est bien entendu la goutte d’eau (découverte aujourd’hui) qui fait déborder la piscine.

J’ai fait un très mauvais choix de technologie avec SQLite3 pour leed, je l’assume intégralement et compte proposer très rapidement une version MySQL, la version SQLite ne sera plus maintenant.

 

Bien à vous.

47 réactions au sujet de « Leed : Pourquoi SQLite3 est un mauvais choix »

  1. sebsauvage Réponse

    Et pourquoi pas sous forme de fichiers ?

    J’ai un bon retour avec Shaarli et ZeroBin (bien qu’ils utilisent des systèmes différents). Mitsukarenai utilise également des fichiers dans Magnesia et ça semble bien booster. (http://sebsauvage.net/links/?-WhOXg)

    Bien géré, on a d’excellentes performances, et sans avoir à se coltiner mySQL (dont en facilitant l’accès à l’application aux utilisateurs débutants).

    • Idleman Auteur ArticleRéponse

      Dans l’absolus je suis d’accord avec toi, mais dans le cas de leed la masse de données est tellement importante que je ne m’en sort pas question performances même en utilisant du gzinflate/gzdeflate à foison… de plus je fais suffisamment de relationnel dans leed pour que le passage aux fichiers texte pleins me causent de très gros ennuis ^^.

      En revanche pour les script contenant un volume moyen de données je suis 100% d’accord, d’ailleurs je sort un article demain sur un petit script utilisant le txt + inflate/deflate à la zerobin/shaarli 🙂

  2. tony Réponse

    >A partir d’une certaine quantité de données, SQLite réagit au final plus lentement que de plus gros poissons comme MySQL

    As tu utilisé des indexes ?

    • Idleman Auteur ArticleRéponse

      Non, je ne souhaitais pas ralentir d’avantage les insertions au profit des sélection etant donné que l’import et la synchro était déjà suffisamment long :), mais même sans ça, la taille du fichier devenait dans tous les cas trop importante et PHP ne semblais plus vouloir la gérer.

      Je pense qu’un script devant gérer des données en masses comme Leed ne peux tous simplement pas se permettre d’utiliser ce genre de technos.

      • tony Réponse

        Je crois me souvenir d’un fil sur stackoverflow ou un dev n’arrivait pas pour son soft à atteindre la vitesse voulue comparée à MySQL, l’utilisation d’indexes avait résolu son problème.

        >verrouillé

        Pour ta base verrouillée, fait tu des accès concurrent en écriture ? Il me semble que c’est le cas au SQLite peut s’engorger. As tu les flags avec lesquels la base que tu utilises à été compilée (-DSQLITE_THREADSAFE etc) ?

        • Idleman Auteur ArticleRéponse

          Comme je te l’ai dis, l’utilisation d’index augmenterais effectivement la perf en lecture du programme, mais la diminuerais en ecriture, hors j’ai de plus grosse lacune du coté de l’écriture (a cause de l’import/synchronisation de données).

          Je ne pense pas avoir fait d’accès concurrent non, cela dis sqlite est sensé gérer ça sans problème si on en crois la doc.

          En ce qui concerne les flags, j’ignore de quoi tu parles 🙂

          J’ai changé la base de Leed, la dernière révision est maintenant sous MySQL, et curieusement j’ai gagné en lecture comme en écriture sur la perf (du moins sur les tests de mon serveur)…

          Un autre avantage à avoir migré sur MySQL est que beaucoup de host comprennent une BDD MySQL par défaut mais aucune possibilité d’activer SQLite (sauf ovh et quelques autres via un .htacess)

        • tony Réponse

          Voilà le fil en question http://stackoverflow.com/questions/54998/how-scalable-is-sqlite:

          “another edit: Since I posted this almost 3 months ago I’ve had the opportunity to closely examine the scalability of SQLite, and with a few tricks it can be quite scalable. As I mentioned in my first edit, database indexes dramatically reduce query time, but this is more of a general observation about databases than it is about SQLite. However, there is another trick you can use to speed up SQLite: transactions. Whenever you have to do multiple database writes, put them inside a transaction. Instead of writing to (and locking) the file each and every time a write query is issued, the write will only happen once when the transaction completes.”

          Ton post m’interpelle car j’utilise de grosses bases SQLite3 -même en write accès concurrent- et je ne me retrouve pas dans ce que tu expérimentes (sauf au niveau des locks, mais avec les retry qui vont bien ça passe ; et je ne suis pas encore sûr que ce problème ne vient pas d’un mauvais design).

          • tony

            > En ce qui concerne les flags

            Il se peut que la base que tu utilises n’est pas bien configurée pour tes besoins, voilà par exemple comment est compilée SQLite3 pour Python sous Android (PY4A):

            LOCAL_CFLAGS += -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_THREADSAFE=1 -DNDEBUG=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_BACKWARDS

          • tony

            J’ai regardé un peu le code de la rev54 de leed, dans ta class SQLiteEntity il y beaucoup de code SQL avec WHERE et AND (sur des UPDATE et SELECT), c’est vraiment pour ces queries que les indexes optimizent le fonctionnement de ta base, e.g. quand tu as un WHERE combiné avec un AND tu utilises un indexe type (compound indexes?):

            CREATE INDEX xxx_01 ON yyy(aaa, bbb)

            “For SELECTs and UPDATEs, indexes can things up, but only if the indexes you create can actually be used by the queries that you need speeding up. Use EXPLAIN QUERY PLAN on your queries to see which index would be used or if the query requires a full table scan. For large tables, a full table scan is bad and you probably want an index. Only one index will be used on any given query. If you have multiple predicates, then the index that will be used is the one that is expected to reduce the result set the most (based on ANALYZE). You can have indexes that contain multiple columns (to assist queries with multiple predicates). If you have indexes with multiple columns, they are usable only if the predicates fit the index from left to right with no gaps (but unused columns at the end are fine). If you use an ordering predicate (<, etc) then that needs to be in the last used column of the index. Using both WHERE predicates and ORDER BY both require an index and SQLite can only use one, so that can be a point where performance suffers. The more indexes you have, the slower your INSERTs will be, so you will have to work out the best trade-off for your situation.”

            Je ne connais pas PHP, mais par exemple pour Python il faut faire attention, ce doc se lit vite et est top (regarde la partie sur les transactions):

            http://chrisniswander.com/presentations/2009/Optimizing%20pysqlite%20databases%20and%20queries/part_1/
            http://chrisniswander.com/presentations/2009/Optimizing%20pysqlite%20databases%20and%20queries/part_2/

            “…Explicitly combining many queries into a single transaction can speed awesomely.
            roughly, queries per time period: from dozens to thousands per time period.

            Transactions have (a) weird difference(s) in different versions of pysqlite.
            Default in version bundled with Python 2.5.x can be that each query is in its own transaction.
            This is horrible because:
            You often need >1 query in one transaction for db integrity.
            Also, … optimize speed of db writes
            …”

            BTW une base de qq MB c’est tout petit, doit y avoir un os quelque part. Je pense que ton choix est fait, mais si tu as le temps d’optimiser ta base SQLite je pense que tu ne voudras plus de SQL 😉

    • Idleman Auteur ArticleRéponse

      Ben voyon 🙂 tu vas me dire si tu me code le connecteur pstgre apres ca s adapte facilement a leed 🙂

  3. Adren Réponse

    Moi aussi je suis d’accord que SQLite est un bon choix dans certains cas très “light” (comme son nom l’indique), mais franchement je ne le remplacerais pour rien au monde par MySQL :

    une cata depuis que Oracle l’a récupéré (licence hell, incertitudes sur le dev et le support, moteur InnoDB vs …)

    l’exemple le plus frappant c’est l’exploit sécu qui vient juste de sortir

    à titre perso, c’est “PostgreSQL rulez (c)(tm)”

    à part des frains psychologique due à l’effet réseau / inertie des habitudes, il n’y a quasi plus de différences entre les 2 logiciels (au contraire d’ailleurs : en terme de perf ou de respect des normes, Postgresql est AMHA bien mieux)

    disclaimer:
    no troll intended

    • Idleman Auteur ArticleRéponse

      Pour le moment MySQL reste le principal SGBD utilisé un peu partout (je parle notamment des hébergements simples type ovh,1and1 etc..) ça reste gratuit et ça reste suffisamment performant a mon sens.

      Après c’est vrai qu’étant donné qu’oracle salis tous ce qu’il rachète je ne fais pas grand cas du SGBD d’ici quelques années, mais bon on a le temps de voir venir pour Leed :p

  4. le hollandais volant Réponse

    Actuellement je suis une phase d’optimisation de SQLite pour Blogotext : utilisation des Indexes, benchmarks sur différents choix, etc…

    Les indexes sur les ID des articles par exemple prend un peu de place dans le fichier .sqlite, mais la performances sont réelles : c’est au moins 4 fois plus rapide.

    Sachant que l’utilisation d’indexes ralentit l’insertion de données mais accèlère la lecture, dans Blogotext le choix est très vite : le nombre de lectures est largement plus grand que le nombre d’écritures dans la base.

    Pour Leed, c’est à voir : j’imagine que le rafraîchissement des flux donne suite à une importante phase d’écriture dans la base…
    As-tu tenté d’utiliser les insertions multiples, au lieu de multiples insertions ? http://lehollandaisvolant.net/tuto/sqlite/#paddentries
    Ce détail est crucial et lors de l’import/export de 8000 entrées, je suis passé de 20 minutes à 2 secondes.

    • Idleman Auteur ArticleRéponse

      Oui toutes les insertions sont groupées :), mais bon ça pompe a mort le parsage de flux, sur un nombre de flux moyen (environ 100) je met entre 80 et 130 secondes pour executer l’import, j’ai du dégager le timeout pour que le script aille jsuqu’au bout je n’imagine même pas si je freinais encore l’écriture.

      Ce qui me gène n’est pas uniquement la rapidité de lecture des items (bien que toutes techniques améliorant la performance sit bonne a prendre sur leed) mais aussi le fait que SQLite semble peiner à gérer au delà d’une certaine quantité de données.

      Sur une moyenne de 150 flux comprenant chacun environ 5 nouveaux events par jour constitués d’un titre, une description, un contenu d’article, une date, un auteur et quelques meta données annexes ça pique vite fait bien fait au bout d’un mois ou deux.

      J’ai bien entendu mis en place un système de rotation mais même en le poussant à fond SQLite reste à la traîne, je pense qu’il ne s’agit tous simplement pas de la bonne technologie quand il s’agit de gérer un très grand nombre de données.

      Et puis il y a également les prérequis serveur et la disponibilité de la technologie sur les simples host à prendre en compte.

      Tu en est ou sur le dev de blogo? il me tarde de voir l’aboutissement de la chose :D, seul le temps nous diras si le choix du sqlite était intéressant pour un blog ou pas, en tous cas c’est un challenge 🙂

      • le hollandais volant Réponse

        Deux minutes pour 100 Inserts ?
        C’est pas mal en effet :o. Ça fait plus d’une seconde par insert…

        T’es sûr que c’est pas la récupération du flux qui prend du temps aussi ?

        • Idleman Auteur ArticleRéponse

          C’est plus 500 inserts que 100 étant donné qu’il y a 100 flux avec en moyenne 5 nouveaux events, cela dis tu as tous a fait raison, la phase la plus lente est la récupération du flux lui même, mais comme je ne peux pas rogner sur cette partie la je me concentre sur l’amélioration des transactions avec la bdd 🙂

          • tony

            Est-ce que ta récup des flux et leur insertion est “async” ? Tu pourrais avoir une ou plusieurs thread qui collectent les flux et les placent dans une pile, et de l’autre coté tu consommes ta pile tant qu’il y a qqch à insérer.

          • Idleman Auteur Article

            Le problème étant que PHP n’est pas vraiment conçu pour le multi-thread, je suis donc en synchrone à l’heure actuelle, il y à des solutions bidouilles pour simuler un multi thread et passer en asynchrone mais je n’ai pas encore eu le temps de m’y consacrer, de plus ces bidouilles nécessitent souvent des prérequis serveurs (comme la technique de passer par curl par exemple)

  5. GoustiFruit Réponse

    Je ne sais pas comment fonctionne un agrégateur de flux, est-ce que les accès concurrents en écriture sont si nombreux que ça par rapport aux accès en lecture ???
    Question c*n aussi, est-ce que tu utilises les transactions lors des insertions/updates ?
    Parce que je suis un peu étonné par ce que tu dis, en ce moment je suis sur un petit projet de “scraping” de résultats foot, je stocke mes données dans une base SQLite3 et je ne constate aucun ralentissement bien que mon fichier fasse désormais près de 70 Mo…

    • Idleman Auteur ArticleRéponse

      Hé bien, lors de la synchronisation des flux avec la base, il y a effectivement une énorme charge en écriture. Après la lecture reste supérieure à l’écriture sur une utilisation normal

  6. gerard Réponse

    Ton article ne m’étonne qu’à moitié. Sqlite ne semble plus aussi avantageux qu’à une certaine époque. J’ai lu vite fait sur le Web – et c’est donc à prendre avec des pincettes – que les prochaines versions de PHP n’intégreraient plus le support de Sqlite.

    C’était bien tenté quand même. En fait il faudrait un truc entre Sqlite et MySql, parce que ce dernier reste quand même gourmand ; d’autant plus quand c’est juste pour une base de données de quelques Mo. Pis du coup, quitte à installer Mysql, autant en profiter pour utiliser les logiciels qui le supportent (que ce soit en moteur de blog, gallery, etc…)

    C’est quand même dommage ct’histoire.

    Du coup va falloir que tu nous pondes un sacré truc, parce que tu vas être en concurrence avec RSSLounge 🙂

    • Idleman Auteur ArticleRéponse

      Arf, effectivement si PHP se met a abandonner la techno c’est inquiétant ^^.

      Personnellement je n’ai rien contre MySQL, il est effectivement un peu plus gourmand que SQLite mais il peut gérer plus de données, utiliser des requêtes plus complexes (permettant d’optimiser les appels), il est disponible à peu près partout et il est plus simple d’accès pour l’administration, bref je ne suis pas trop peiné d’y passer, de plus après tests il semble que la version de Leed pour MySQL soit plus rapide que celle pour SQLite (certainement du a la grosse quantité de données et a une mauvaise gestion de la techno de ma part)du coups je suis assez content du changement.

      Je ne ferais jamais concurrence a RSSlounge pour la simple et bonne raison que Leed a pour unique but la performance et que RSSLounge a pour unique but d’apporter le café 😀 (si les auteurs d’RSS lounge passent par la, toutes mes excuses pour la blagounette)

    • GoustiFruit Réponse

      SQLite reste quand même utilisé par la plupart des navigateurs (tous ?) pour le stockage offline, et Firefox, Opera, Chrome l’utilisent aussi en interne, c’est aussi la base de données par défaut dans les produits portables Apple et Androïd il me semble… Ca ne doit pas être si mauvais que ça !?

      • Idleman Auteur ArticleRéponse

        Je pense qu’SQlite est très bien pour stocker les configurations les programmes bureautiques ou un nombre de données réduites (par réduites j’entends pas plus de quelques milliers d’entrées), en revanche après tests je pense qu’il ne s’agit pas d’une technologie bien adaptée a un projet web PHP devant gérer un gros nombre d’informations.

  7. bajazet Réponse

    Simple question, tu récupères tous les flux et ensuite tu envoies ou bien tu récupères tu insères ?

      • Idleman Auteur ArticleRéponse

        Non, mais j’ai tenté le gzinflfate/delfate qui est plus performant (car meilleur compression des données)

    • Idleman Auteur ArticleRéponse

      Insertion groupée par flux, évidemment ça serais encore mieux d’envoyer toutes les requêtes en même temps mais ça casserait la logique de mon connecteur generique ORM.

    • Idleman Auteur ArticleRéponse

      Leed n’est pas un blog mais un agrégateur RSS, ce qui signifie qu’il ne dois pas stocker et gérer un ou deux posts par jour mais 100 ou plus (en fonction du nombre de flux), ce qui complique grandement la tâche à xml 😀

  8. gerard Réponse

    Rhaaaa ! T’as fait la boulette !

    On ne fait pas héberger Jquery par Google ! En plus la taille du fichier jquery-min est tout petit, y a vraiment aucun intérêt de le faire.

  9. GoustiFruit Réponse

    Astuce que j’ai également postée chez LHV; pas encore testée chez moi vu que les performances de ma BDD SQLite sont satisfaisantes, mais si l’un d’entre-vous a envie de tester et de comparer…

    PRAGMA temp_store=MEMORY
    PRAGMA synchronous=OFF
    PRAGMA default_cache_size = 10000

    • Idleman Auteur ArticleRéponse

      Désolé pour le temps de réponse, j’étais en vacances dans les alpes (et c’était bon :p)

      C’est a placer dans la requête de construction de la BDD?

      Sais tu quels points ça améliore concrètement ? En tut cas merci pour l’astuce 🙂

  10. OranginaRouge Réponse

    Petites questions d’ordre pratique :
    # Lorsque l’on récupérère le projet via une archive sur Dizplay, est-ce que l’on a la dernière version présente sur le SVN ?
    # Selon le fichier README, j’ai récupéré la version 1.0 Alpha ; pareillement, est-ce que cela correspond à la dernière version SVN ?

    Petite remarque en passant, je salut ton projet DizPlay mais quelle dommage cette longue arborescence de sous dossier pour récupérer les fichiers 😛 (du type mondossier\leed\home\ftp\www\Dizplay\Projects\Archives\leed…)

    • Idleman Auteur ArticleRéponse

      Désolé pour le temps de réponse, j’étais en vacances dans les alpes (et c’était bon :p)

      Pour le point 1, si j’ai bien fait mon boulot ( a savoir que j’ai bien appuyé sur le bouton “déployer” après commit) l’archive correspond bien a la dernière révision du svn 🙂

      Pour le fichier README, j’oublie déjà plus souvent de le mettre a jour désolé 😀 je suis un peu tête en l’air.

      On m’a déjà fait la remarque pour l’arborescence de dizplay, et je suis tout à fait d’accord ça n’est pas top ^^, je n’ai pas encore eu le temps de m’en charger, il faut juste que je trouve la bonne commande linux qui ne remet pas tous le chemin dans l’archive :D, normalement pour le format 7z, le problème n’est plus. 🙂

  11. cyberic Réponse

    Je vote aussi pour la ré-inclusion de sqldb, ou alors par fichier.
    Ou alors….
    plusieurs plus petits fichiers SQLdb…
    par exemple un fichier sqldb par flux…
    ça permet d’éviter les pb de synchro et de paralléliser
    par contre oui, si on lance un recherche globale, il faut parcourir chaque base une par une….

    • Idleman Auteur ArticleRéponse

      Un par flux c’est un peu bourrin ^^, peut être ferais je une version pour sqlite en db fractionné mais j’attends que la version 1 soit totalement stable (encore deux petits bugs a régler)

  12. tony Réponse

    Hello !

    Je reviens un peu sur sqlite au vu de mes derniers tests.

    J’utilisais sqlite avec Python 2.7, je me suis rendu compte que la version était 3.6.21, quelle version utilisais tu ?

    J’ai été pas mal embêté avec l’exception “OperationalError(‘database is locked’)” [pas de problème de vitesse pour moi], en gros quand un select était toujours actif sur une table, pas moyen d’écrire dessus. Du coup je suis passé à sqlite 3.7 (je me demande pourquoi le build de python était toujours en 3.6 !?) pour pouvoir utiliser le WAL (Write-Ahead Logging): http://www.sqlite.org/draft/wal.html

    Maintenant fini les problèmes de DB locked.

    My two cents…

    • Idleman Auteur ArticleRéponse

      Ça commence a dater, j’ignore quelle version de sqlite était installée sur mon serveur à cette époque, il faudra que je refasse des tests 🙂

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.