GRDB pour SQLite

Une bonne alternative à  FMDB pour Swift pour ceux qui utilisent SQLite mais pas CoreData ?


https://github.com/groue/GRDB.swift


 


(bien que FMDB soit maintenant compatible avec Swift)


Réponses

  • Moi je suis satisfait de FMDB en Objective C et je suppose que ça doit être la même chose sur Swift.


    Je ne vois pas de raison de changer :)


  • Bonjour,


     


    Je suis l'auteur de GRDB.swift.


     


    Les utilisateurs de fmdb se sentiront à  l'aise avec GRDB.


     


    Ils trouveront peut-être que charger lignes et valeurs sera plus facile avec GRDB, parce qu'au lieu d'itérer à  la main FMResultSet, et de les fermer à  la main quand on ne veut qu'une seule ligne, GRDB charge des collections standard de Swift, ou même de simples valeurs comme Int, String, ou NSDate.


     


    Ensuite, GRDB gère proprement les erreurs de SQLite, quand fmdb ne respecte pas les conventions classiques autour de NSError.


     


    Ceci dit, GRDB a été grandement inspiré par fmdb: je ne suis qu'un nain sur les épaules d'un géant !


  • muqaddarmuqaddar Administrateur
    septembre 2015 modifié #4

    Est-ce qu'il peut y avoir une différence de performance sur une itération de 5000 lignes contenant une vingtaine de champs (c'est arbitraire) entre FMDB et GRDB ? Puisque les méthodes ne semblent pas les mêmes.


  • C'est à  tester, je ne sais pas encore. GRDB charge les lignes une à  une, comme fmdb. Il n'y a pas vraiment de différence de méthode, plus une différence d'écosystème (Objective-C d'un côté, et Swift de l'autre). Ce serait bon de connaà®tre la réponse à  ta question, en tout cas : merci pour ta suggestion.
  • Salut muqaddar.


     


    Bon, voilà  les choses en l'état.


     


    Le code ci-dessous tourne, sur ma machine, en:


     


    - GRDB: 0.319s (3% STDEV)


    - FMDB: 0.070s (4% STDEV)


     


    Donc l'avantage est clairement à  FMDB. J'ai encore un peu de boulot.


     


    class FMDBBenchmarksTests: XCTestCase {


        func testGRDBPerformanceExample() {


            let path = "/tmp/GRDB.sqlite"


            do { try NSFileManager.defaultManager().removeItemAtPath(path) } catch { }


            let dbQueue = FMDatabaseQueue(path: path)


            dbQueue.inDatabase { db in


                db.executeUpdate("CREATE TABLE items (i0 INT, i1 INT, i2 INT, i3 INT, i4 INT, i5 INT, i6 INT, i7 INT, i8 INT, i9 INT)", withArgumentsInArray: nil)


                for i in (0..<10000) {


                    db.executeUpdate("INSERT INTO items (i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) VALUES (?,?,?,?,?,?,?,?,?,?)", withArgumentsInArray: [i % 3, i % 4, i % 5, i % 6, i % 7, i % 8, i % 9, i % 10, i % 11, i % 12])


                }


            }


            


            // This is an example of a performance test case.


            self.measureBlock {


                var sum: Int64 = 0


                dbQueue.inDatabase { db in


                    if let rs = db.executeQuery("SELECT * FROM items", withArgumentsInArray: nil) {


                        while rs.next() {


                            let i0 = rs.longLongIntForColumn("i0")


                            let i1 = rs.longLongIntForColumn("i1")


                            let i2 = rs.longLongIntForColumn("i2")


                            let i3 = rs.longLongIntForColumn("i3")


                            let i4 = rs.longLongIntForColumn("i4")


                            let i5 = rs.longLongIntForColumn("i5")


                            let i6 = rs.longLongIntForColumn("i6")


                            let i7 = rs.longLongIntForColumn("i7")


                            let i8 = rs.longLongIntForColumn("i8")


                            let i9 = rs.longLongIntForColumn("i9")


                            sum += i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9


                        }


                    }


                }


                NSLog("FMDB sum: \(sum)")


            }


        }    


    }


     

    class GRDBBenchmarksTests: XCTestCase {

        func testGRDBPerformanceExample() {


            let path = "/tmp/GRDB.sqlite"


            do { try NSFileManager.defaultManager().removeItemAtPath(path) } catch { }


            let dbQueue = try! DatabaseQueue(path: path)


            try! dbQueue.inDatabase { db in


                try db.execute("CREATE TABLE items (i0 INT, i1 INT, i2 INT, i3 INT, i4 INT, i5 INT, i6 INT, i7 INT, i8 INT, i9 INT)")


                for i in (0..<10000) {


                    try db.execute("INSERT INTO items (i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) VALUES (?,?,?,?,?,?,?,?,?,?)", arguments: [i % 3, i % 4, i % 5, i % 6, i % 7, i % 8, i % 9, i % 10, i % 11, i % 12])


                }


            }


            


            // This is an example of a performance test case.


            self.measureBlock {


                var sum: Int64 = 0


                dbQueue.inDatabase { db in


                    for row in Row.fetch(db, "SELECT * FROM items") {


                        let i0: Int64 = row.value(named: "i0")!


                        let i1: Int64 = row.value(named: "i1")!


                        let i2: Int64 = row.value(named: "i2")!


                        let i3: Int64 = row.value(named: "i3")!


                        let i4: Int64 = row.value(named: "i4")!


                        let i5: Int64 = row.value(named: "i5")!


                        let i6: Int64 = row.value(named: "i6")!


                        let i7: Int64 = row.value(named: "i7")!


                        let i8: Int64 = row.value(named: "i8")!


                        let i9: Int64 = row.value(named: "i9")!


                        sum += i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9


                    }


                }


                NSLog("GRDB sum: \(sum)")


            }


        }


    }

  • muqaddarmuqaddar Administrateur

    Merci pour le test.


     


    Je ne sais pas comment marche row.value().


     


    Avec FMDB je me souviens de très grosses différences de performances entre l'appel de l'index du champ et l'appel du nom du champ lui-même. Donc je pense qu'il peut encore être plus rapide.



    - (long long int)longLongIntForColumn:(NSString*)columnName {
        return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]];
    }

    - (long long int)longLongIntForColumnIndex:(int)columnIdx {
        return sqlite3_column_int64([_statement statement], columnIdx);
    }
  • grouegroue Membre
    septembre 2015 modifié #8

    J'ai refait les tests en configuration Release, et https://github.com/groue/GRDB.swift donne des chiffres plus réalistes : en l'état actuel des choses, GRDB est 4 fois plus lent que fmdb à  traiter des lignes.


  • Désormais les performances de GRDB sont meilleures que celles de SQLite.swift et FMDB : https://github.com/groue/GRDB.swift/wiki/Performance


  • Ca a l'air bien.


    Est-ce que ça pourrait compiler sous Linux ?


  • muqaddarmuqaddar Administrateur


    Désormais les performances de GRDB sont meilleures que celles de SQLite.swift et FMDB : https://github.com/groue/GRDB.swift/wiki/Performance




     


    Oui, je suis ce qui se passe sur ce framework depuis quelques temps et j'avais vu les différences. Intéressant.


    Je pense passer à  GRDB quand je passerai mon appli à  Swift, dans quelques mois. J'attends Swift 3 et je vois que tu suis bien les évolutions de Swift.



  • Ca a l'air bien.


    Est-ce que ça pourrait compiler sous Linux ?




     


     


    Je ne travaille pas sur Linux, donc je n'ai pas fait l'effort de m'en assurer. De plus GRDB utilise Foundation pour quelques fondamentaux, comme NSData pour les blobs. Mais la qualité de Foundation sur linux est encore vacillante. En résumé : toutes les contributions sont bienvenues, mais il ne faut pas être trop pressé ni croire que tout va marcher comme sur des roulettes sans effort sérieux.



  • Oui, je suis ce qui se passe sur ce framework depuis quelques temps et j'avais vu les différences. Intéressant.


    Je pense passer à  GRDB quand je passerai mon appli à  Swift, dans quelques mois. J'attends Swift 3 et je vois que tu suis bien les évolutions de Swift.




     


    Tu fais exactement ce que tu veux : je n'ai pas écrit cette lib pour toi ni dans l'attente de ton jugement, mais parce que j'en ai besoin et que je veux fournir du code correct à  moi-même et mes collègues.



  • Tu fais exactement ce que tu veux : je n'ai pas écrit cette lib pour toi ni dans l'attente de ton jugement, mais parce que j'en ai besoin et que je veux fournir du code correct à  moi-même et mes collègues.




    Su tu n'attends pas un jugement des autres, je ne vois pas l'intérêt de la mettre en open source. 



  • Tu fais exactement ce que tu veux : je n'ai pas écrit cette lib pour toi ni dans l'attente de ton jugement, mais parce que j'en ai besoin et que je veux fournir du code correct à  moi-même et mes collègues.




    Oh mais que c'est bon esprit tout ça ! 

  • Comprenez-moi bien : lire qu'on daignera jeter un regard sur mon travail si "je suis bien les évolutions de Swift", ce n'est pas agréable.


  • muqaddarmuqaddar Administrateur


    Tu fais exactement ce que tu veux : je n'ai pas écrit cette lib pour toi ni dans l'attente de ton jugement, mais parce que j'en ai besoin et que je veux fournir du code correct à  moi-même et mes collègues.




     


    Heu, je n'ai pas tout compris... Je te faisais justement un compliment en disant que tu suivais de près les évolutions de Swift.  Et que quant à  moi, j'attendais Swift 3 pour passer à  Swift.

  • muqaddarmuqaddar Administrateur


    Comprenez-moi bien : lire qu'on daignera jeter un regard sur mon travail si "je suis bien les évolutions de Swift", ce n'est pas agréable.




     


    Ce n'est pas du tout le sens de ma phrase, m'enfin...  ::)

  • ... oups, je me suis complètement trompé sur le sens de ta phrase, tu as raison !


     


    Toutes mes excuses, je t'ai cru à  tord hautain et dédaigneux... Et désolé aussi pour la pollution du thread. ça m'apprendra à  mal lire.


     


    Hé bien du coup, merci, et j'espère que tu apprécieras GRDB si tu utilises SQLite quand Swift 3 sortira ! Va aussi voir https://medium.com/@gwendal.roue/grdb-stories-993b9d016867, c'est une suite de petites histoires courtes autour de GRDB qui montrent, j'espère, que la lib est là  pour rendre service.


  • LarmeLarme Membre
    avril 2016 modifié #20


    Ce n'est pas du tout le sens de ma phrase, m'enfin...  ::)




    J'ai compris ce que tu voulais dire.


    En un peu plus explicite, Swift, c'est des changements (1.0, 2.0, 2.2) et encore, je ne suis au courant que parce que je passe sur StackOverflow et que je vois nombre de questions " Comment faire pour passer mon code dans la version supérieure parce que maintenant ça ne compile plus ? Ouin ouin ", et j'ai compris que muqaddar te félicitait d'updater ton code aux dernières versions Swift.


    D'avoir du code maintenu en bref.


     


    Maintenant, si tu n'es intéressé que pour partager le code avec toi-même et quelques développeurs/collègues triés sur le volet, je te conseillerais peut-être d'avoir un repo de git privé.


    Car un repo public, entraà®nera souvent des remontées de tickets de bugs, des propositions d'améliorations (que ce soit des pulls requests ou des gens qui voudront telle fonctionnalité mais ne voudront pas ou ne sauront pas la coder), etc. Et le SAV, à  moins de l'accepter...


    La " magie d'Internet " en quelque sorte.


  • muqaddarmuqaddar Administrateur
    avril 2016 modifié #21


    ... oups, je me suis complètement trompé sur le sens de ta phrase, tu as raison !


     


    Toutes mes excuses, je t'ai cru à  tord hautain et dédaigneux... Et désolé aussi pour la pollution du thread. ça m'apprendra à  mal lire.


     


    Hé bien du coup, merci, et j'espère que tu apprécieras GRDB si tu utilises SQLite quand Swift 3 sortira ! Va aussi voir https://medium.com/@gwendal.roue/grdb-stories-993b9d016867, c'est une suite de petites histoires courtes autour de GRDB qui montrent, j'espère, que la lib est là  pour rendre service.




     


    Ah, je préfère ceci ! J'ai pensé à  un "accident de lecture" aussi.


    J'ai vu qu'il existe 4 ou 5 librairies SQLite Swift et la tienne me paraà®t la meilleure, et la plus complète.


     


    J'irais lire les histoires sur Medium, mais celle qui me plaà®t le plus est celle sur la concurrence entre une action réseau et une action locale.


     


    La façon dont tu écris les requêtes ressemble à  ActiveRecord, donc ça me plaà®t en tant que "Rails addict". Cela dit, je ne suis pas sûr de l'utiliser, car écrire du pur SQL est un avantage en cas de portage multi-plateformes.


     


    Sinon, j'utilise actuellement SQLCipher pour encrypter la base. C'est compatible avec FMDB, je ne sais pas si ça le serait avec GRDB. Mais à  l'heure actuelle, je ne sais même pas si je vais le garder dans mon app de toute façon.


  • Là  maintenant c'est bon esprit  :)


     


    @Larme: généralement les gens ne se plaignent pas du fait que leur code ne fonctionne pas mais plutôt du fait qu'un code trouvé sur le net n'est pas compatible avec la version de Swift que tu as. Si tu fais du Swift de manieÌ€re sérieuse et journalière tu es censé être au courant des changements. (enfin normalement)




  • Maintenant, si tu n'es intéressé que pour partager le code avec toi-même et quelques développeurs/collègues triés sur le volet, je te conseillerais peut-être d'avoir un repo de git privé.


    Car un repo public, entraà®nera souvent des remontées de tickets de bugs, des propositions d'améliorations (que ce soit des pulls requests ou des gens qui voudront telle fonctionnalité mais ne voudront pas ou ne sauront pas la coder), etc. Et le SAV, à  moins de l'accepter...


    La " magie d'Internet " en quelque sorte.




     


    Salut Larme. Tu as vu, c'était un quiproquo. Et tu verras que si GRDB n'a pas d'issue ouverte sur Github, ce n'est pas parce que la lib est confidentielle, mais parce que je réponds aux demandes de la communauté. Et tu verras peut-être aussi que j'ai mis en ligne GRMustache et GRMustache.swift, deux libs qui ont leur petit succès, et aussi mon attention quant aux questions des développeurs. ça fait quelques années que je maintiens du code et suis plongé dans la magie d'Internet !


     


    Puisque tu la connais, cette magie, alors tu sais que la naiveté ne tient pas longtemps, parce que tu finis par être confronté à  des gens vraiment désagréables, que tu n'as pas du tout envie d'aider. Et répondre sèchement aux gens fais partie, à  tord ou à  raison, de mon arsenal de réponses. Je suis désolé d'avoir cru que muqaddar était de ce type : c'était le quiproquo.



  • Ah, je préfère ceci ! J'ai pensé à  un "accident de lecture" aussi.


    [...]


    Sinon, j'utilise actuellement SQLCipher pour encrypter la base. C'est compatible avec FMDB, je ne sais pas si ça le serait avec GRDB. Mais à  l'heure actuelle, je ne sais même pas si je vais le garder dans mon app de toute façon.




     


     


    Bon, je suis soulagé !


     


    GRDB a sa patte pour SQLCipher: https://github.com/groue/GRDB.swift#encryption, pour le jour ou tu voudras l'utiliser.



  • La façon dont tu écris les requêtes ressemble à  ActiveRecord, donc ça me plaà®t en tant que "Rails addict". Cela dit, je ne suis pas sûr de l'utiliser, car écrire du pur SQL est un avantage en cas de portage multi-plateformes.




    Moi pareil. J'ai ajouté la "query interface" pour que mon collègue qui n'est pas encore très à  l'aise avec SQL ne se sente pas trop perdu.

  • muqaddarmuqaddar Administrateur


    Bon, je suis soulagé !


     


    GRDB a sa patte pour SQLCipher: https://github.com/groue/GRDB.swift#encryption, pour le jour ou tu voudras l'utiliser.




     


    Super, je n'avais pas vu. Merci.


     




    Moi pareil. J'ai ajouté la "query interface" pour que mon collègue qui n'est pas encore très à  l'aise avec SQL ne se sente pas trop perdu.




     


    Oui, ça permet de contrôler un peu mieux les jointures aussi (cas typique du includes() et du join() en Rails qui ne font pas la même chose au niveaux requêtes).

  • CéroceCéroce Membre, Modérateur

    Déterrage de topic!


     


    J'ai utilisé GRDB sur mon dernier projet. J'en suis franchement heureux. Je réitère à  @groue les remerciements déjà  faits sur Twitter.


     


    - le code est super-propre


    - la documentation est complète


    - j'ai eu des soucis de performances avec SQLite, mais j'ai pu 1) utiliser les transactions, prévues par l'auteur et implémentées de façon élégante 2) désactiver certains contrôles de SQLite.


    - je n'ai eu aucune galère. Les rares soucis découlaient d'incompréhensions de ma part, pas d'erreurs de conception.


    - je suis très loin d'en avoir fait le tour, mais la courbe d'apprentissage est très raisonnable pour les opérations courantes.


     


    Et en plus, elle évolue bien:


    - passage à  Swift 4 rapidement après la mise à  disposition de Xcode 9.


    - les Records peuvent utiliser le protocole Codable ce qui épargne du code inutile.


    - il existe depuis peu une extension pour l'interfacer avec RxSwift! Si, si. 

  • Le projet a l'air sympa, dommage qu'il n'y ai pas un exemple complet pour les 'Records'

  • CéroceCéroce Membre, Modérateur

    Si justement, il n'y a qu'un seul exemple (un peu léger) mais qui démontre comment utiliser le FetchedRecordsController et aussi les Records.

  • @Céroce a dit :
    Si justement, il n'y a qu'un seul exemple (un peu léger) mais qui démontre comment utiliser le FetchedRecordsController et aussi les Records.

    Merci pour l'info, je vais regarder cela.

Connectez-vous ou Inscrivez-vous pour répondre.