[projet] Gestion de bases de données, choix de conception et performances

muqaddarmuqaddar Administrateur
août 2009 modifié dans Vos applications #1
Bonjour,

Pour un prochain projet, je me pose des questions sur les performances liées à  la gestion des données.

Mon projet s'articulera autour de sqlite.
Mais par exemple pour des tables de valeurs identiques qui ne bougent pas (ou peu ?), je me demande si la gestion de ces tables est nécessaire ou bien s'il ne vaut mieux pas passer par des arrays de constantes, des statics ou autre chose ?

Je m'explique. Imaginons une table A. La table A a un champ "notation" par exemple. Notation peut avoir en gros 10 valeurs qui ne changent jamais (excellent, très bon, bon, mauvais...etc).

La première méthode pourrait être de gérer une table supplémentaire "notations", avec les valeurs et de faire une clé externe de la table A vers la table B, notation_id. C'est pratique et flexible, notamment pour les recherches par clés. Mais ce doit être assez gourmand (je pourrais en effet me retrouver avec 20 tables de ce genre pour mon projet).

Je pense qu'il doit y avoir d'autres solutions moins gourmandes en ressources (et en relationships lors des requêtes SQL, Ram et processeur ?). Que proposez-vous du genre tableau de constantes en dur dans le code ? Dans ce cas, on sauvegarderait la valeur elle-même, et non la clé. J'ajoute que ces valeurs devront être traduites par la suite (pour la flexibilité).

Votre avis ?

Réponses

  • antoine2405antoine2405 Membre
    12:44 modifié #2
    Est ce que tu penses utiliser le framework CoreData ou pas?

    Perso pour répondre a ta question, je pense que sa dépend si tu fais évoluer ton application dans le futur. Ton application sera beaucoup plus flexible si tu utilises une base de donnée contrairement au array...

    Tu vas peu être te prendre plus la tête avec une base de donnée au début mais a la fin tu te rendras compte que tu as gagné pas mal de temps....

    Au niveau des performances j'en sais rien du tout...

  • muqaddarmuqaddar Administrateur
    12:44 modifié #3
    dans 1251196471:

    Est ce que tu penses utiliser le framework CoreData ou pas?

    Perso pour répondre a ta question, je pense que sa dépend si tu fais évoluer ton application dans le futur. Ton application sera beaucoup plus flexible si tu utilises une base de donnée contrairement au array...

    Tu vas peu être te prendre plus la tête avec une base de donnée au début mais a la fin tu te rendras compte que tu as gagné pas mal de temps....

    Au niveau des performances j'en sais rien du tout...




    Ah tu m'as mal lu. ;)
    Oui j'utilise une base de données (je ne peux pas vivre sans...) lol

    Simplement pour quelques relations simples sur des petites quantités de données peu amenées à  évoluer, c'est là  où je me pose la question de faire communiquer avec données fixes ou des relations de tables. Dans tous les cas, il y aura des relations avec d'autres tables plus complexes, mais là  en l'occurence, c'est pour des tables qui ont peu de données.

    Quant à  CoreData, je ne veux pas l'utiliser.
  • antoine2405antoine2405 Membre
    12:44 modifié #4
    C'est pourtant pas mal CoreData quand tu le maà®trise... j'avoue tu trimes pendant 2 semaines mais après tu es bien comptant d'avoir passer 2 semaines a essayer de faire marcher le framework bref ^^

    c'est quoi tu points de vue la dessus ?

    Je ne pense pas qu'il y est question à  se poser. Sa dépend de toi, de ce que tu  préférés ... Le code sera plus propre si tu fais tous rentrer dans une base de donnée.. mais sinon a la fin tu as la même chose...
     
  • CéroceCéroce Membre, Modérateur
    12:44 modifié #5
    dans 1251195616:

    Que proposez-vous du genre tableau de constantes en dur dans le code ? Dans ce cas, on sauvegarderait la valeur elle-même, et non la clé. J'ajoute que ces valeurs devront être traduites par la suite (pour la flexibilité).

    Même si je ne suis pas un spécialiste de la BdD, le plus simple pour l'exemple de la notation, c'est de mettre la note directement dans la table, stockée en INT. Même avec une BdD, il est plus rapide d'utiliser des entiers que des chaà®nes.

    Dans ton code, tu créeras ensuite un tableau de pointeurs vers les chaà®nes de caractères traduites, dont la note est l'index.
  • Fallout88Fallout88 Membre
    12:44 modifié #6
    Bonjour, pour moi il est logique de mettre cela dans une table pour deux raisons, 1 tu dis que des données changeraient très peu mais on est dans l'informatique, le monde du tout ou rien et donc les données doivent pouvoir changer et de 2 tu utiliseras dans tout les cas une base sqlite et tant qu'à  utiliser sqlite autant l'utiliser jusqu'au bout.
    Pour te rassurer, j'utilise actuellement une base en SQLITE3 avec une table très proche de ta table notation (une table qui rassemble toutes les langues dispo) et j'effectue d'assez grosses requêtes et les performances sont plus que surprenantes.
  • muqaddarmuqaddar Administrateur
    août 2009 modifié #7
    dans 1251205021:

    Pour te rassurer, j'utilise actuellement une base en SQLITE3 avec une table très proche de ta table notation (une table qui rassemble toutes les langues dispo) et j'effectue d'assez grosses requêtes et les performances sont plus que surprenantes.


    Sur l'iPhone ?

    J'ai déjà  une appli qui fonctionne en sqlite avec des relations. Cependant, 50 enregistrements ou 5000, ce n'est pas pareil. Donc je me méfie et préfère être sûr avant de coder. ;) Merci.
  • muqaddarmuqaddar Administrateur
    12:44 modifié #8
    dans 1251204205:

    Même si je ne suis pas un spécialiste de la BdD, le plus simple pour l'exemple de la notation, c'est de mettre la note directement dans la table, stockée en INT. Même avec une BdD, il est plus rapide d'utiliser des entiers que des chaà®nes.

    Dans ton code, tu créeras ensuite un tableau de pointeurs vers les chaà®nes de caractères traduites, dont la note est l'index.


    Cette approche me paraà®t plutôt bonne. Merci.
  • Fallout88Fallout88 Membre
    12:44 modifié #9
    On a fait un test avec 100 000 enregistrements, résultat 0.02 Secondes de traitement total MAIS par sur iPhone, je préfère rien dire j'ai pas encore tester dessus
  • muqaddarmuqaddar Administrateur
    12:44 modifié #10
    dans 1251207605:

    On a fait un test avec 100 000 enregistrements, résultat 0.02 Secondes de traitement total MAIS par sur iPhone, je préfère rien dire j'ai pas encore tester dessus


    OK, merci pour les infos Fallout.
  • muqaddarmuqaddar Administrateur
    12:44 modifié #11
    J'ai débroussaillé mon modèle.

    Donc en gros, j'ai une table principale, avec 4 ou 5 tables liées par relations (celles-là  je suis sûr de les créer car elles doivent pouvoir être modiées facilement) + une quinzaine d'autres tables simples avec 5 à  10 valeurs chacune qui n'évolueront pas, et qui doivent aussi être en relation avec la table principale. C'est sur ces tables là  que portait ma question. Elles n'ont que 2 champs en gros (id, name).
  • AliGatorAliGator Membre, Modérateur
    12:44 modifié #12
    Oui mais si tu ne les mets pas dans des tables, ou que tu les mets dans les tables mais les garde en cache quelquepart pour ne les lire qu'une fois au chargement de ton appli par exemple (puisque tu dis qu'elles changent très peu)... bah tu ne pourras alors pas faire de jointures dans tes requêtes SQL ;)
    Donc autant garder les tables, non ?
  • Fallout88Fallout88 Membre
    12:44 modifié #13
    Par contre, je sais pas si tu es habitué à  SQLITE3 mais il existe quelques manques sur les mots clé SQL qui ne sont toujours pas implémenter. Je te dis surtout ça pour les jointures RIGHT et FULL OUTER JOIN mais après je ne sais pas comment tu avais l'intention de gérer ton petit monde mais ça m'a un peu dérouter la première fois.

    Lien pour voir les implémentations manquantes.
    http://www.sqlite.org/omitted.html
  • Fallout88Fallout88 Membre
    12:44 modifié #14
    Pour info SQLite3 gére des caches ;)
  • muqaddarmuqaddar Administrateur
    12:44 modifié #15
    Y'a le LEFT OUTER JOIN c'est déjà  ça.
    Je ne sais pas si j'ai besoin des autres à  l'heure où je parle. ;)
    Je ne suis pas non plus plus calé que ça en SQL.

    Merci pour le lien.
  • muqaddarmuqaddar Administrateur
    août 2009 modifié #16
    dans 1251209751:

    Oui mais si tu ne les mets pas dans des tables, ou que tu les mets dans les tables mais les garde en cache quelquepart pour ne les lire qu'une fois au chargement de ton appli par exemple (puisque tu dis qu'elles changent très peu)... bah tu ne pourras alors pas faire de jointures dans tes requêtes SQL ;)
    Donc autant garder les tables, non ?


    Je ne comprends pas bien.

    Si je ne crée pas de tables, mais des arrays à  la place, et que dans la table principale je stocke 0,1,2... bref un entier qui pointe vers la position dans le tableau, n'est-ce pas moins gourmand qu'une jointure ?

    Les données ne sont pas forcément chargées au démarrage de l'appli, mais quand j'en ai besoin dans l'appli, c'est pour ça que j'aime la flexibilité du SQL.

    Par exemple si j'ai un dessert avec une note, mais que la note n'est affichée que ds le 5è onglet de mon appli, pourquoi je garderai la note en mémoire si je ne vais jamais voir ce 5è onglet ? Je pense qu'il est plus logique d'aller chercher la note que si on se trouve dans cet onglet ?

    Ce qu'il faut bien comprendre c'est que les tables en question ne seront JAMAIS modifiées par le user. Il n'aura droit de modifier que la valeur de la clé externe pointant sur ces tables ou bien sur l'id d'un array.

  • muqaddarmuqaddar Administrateur
    12:44 modifié #17
    J'ai une autre question sur la stratégie de mise à  jour d'une base pour une application.

    Imaginons que mon projet ait une table avec 500 enregistrements.
    Je livre l'appli avec ces 500 enregistrements. Ils sont copiés dans le répertoire User de l'application (je ne m'en suis encore jamais servi sur l'iPhone).

    L'utilisateur veut rentrer 1 nouvel enregistrement dans cette table, car 1 manque à  l'appel.

    Stratégie 1) : je l'autorise, il se crée son record avec ID n° 501 dans son iPhone, mais du coup les autres Users ne peuvent l'utiliser. De plus, un autre User pourra avoir un ID 501 avec une autre valeur... BEURK

    Stratégie 2) : il me le signale, je l'ajoute dans la DB de l'application, et vlà  qu'il faut pas attendre 3 semaines pour qu'Apple valide la nouvelle version : BEURK.

    Stratégie 3) : il me le signale (via l'appli par exemple), je l'ajoute à  ma DB en ligne, et hop l'appli a une fonction de synchronisation qui importe la DB mise à  jour et la recopie dans le répertoire User de l'iPhone. On est sûr que toutes les applis déployées auront l'ID 501 avec la même valeur (qui plus est avec la bonne orthographe). Je dis OUI. De plus, c'est aussi le meilleur choix si l'appli devient communautaire dans le temps.

    Avez-vous mieux (même si la solution 3 est la plus coûteuse en temps ) ?
  • AliGatorAliGator Membre, Modérateur
    12:44 modifié #18
    3 !

    C'est pas si coûteux il suffit de mettre qqpart un XML avec une version pour ta base de données et l'URL où télécharger la base (le fichier .sqlite). Un peu comme un AppCast.
    Ton appli se connecte de temps en temps (au lancement, si l'accessibility dit que tu peux te connecter) pour vérifier la version et si elle a changée supprime le fichier sqlite courant et le remplace par le nouveau. Basta.

    Certes, un peu plus coûteux que la solution 2 d'attendre la validation, mais pas tant plus coûteux que ça que la solution 1 puisque dans cette dernière tu devras prévoir une interface de saisie des données dans ton appli, avec la validation de ces données, etc... donc y'a un peu de boulot aussi, et p'tet même plus que pour la 3.
  • muqaddarmuqaddar Administrateur
    août 2009 modifié #19
    Oui, je suis d'accord avec toi.

    Cependant, la saisie de mes données étant en ligne, je n'ai besoin que d'un fichier sqlite 3 à  faire télécharger. Ce XML n'est que pour vérifier la version de la BDD apparemment ?

    Tu me confirmes que ce fichier est à  mettre dans le rep User de l'utilisateur sur l'iPhone ? (je ne pense pas qu'on puisse avoir les droits pour remplacer celui dans le bundle de l'application...)

    Bon, en tout cas, je trouve cela élégant comme solution.
  • AliGatorAliGator Membre, Modérateur
    12:44 modifié #20
    Oui tout à  fait, je voyais le XML comme un AppCast comme je te dis, c'est à  dire qui ne contient qu'un numéro de version de ta BdD (et éventuellement l'URL à  laquelle aller télécharger ta base / ton fichier sqlite)
    Pour t'éviter ainsi d'avoir à  retélécharger la base de données régulièrement même si elle n'a pas changée. Le XML, lui, est super léger (que qques Ko) à  aller récupérer. Et bon je t'ai parlé d'un XML car d'une part c'est un format standard et utilisé par d'autres trucs similaires comme les AppCasts, mais si tu n'as que la version à  aller vérifier, ça peut être juste un fichier texte contenant la version. Ou une requête vers une page PHP ou Ruby qui va te retourner juste la version.

    Et sinon en effet le fichier est à  mettre dans le rep utilisateur sur l'iPhone (on parle de sandbox, chaque application a un répertoire isolé des autres applications) puisque comme tu l'as noté on ne peut pas modifier le bundle de l'application (normal, d'une part il est "signé" (CodeSigning) mais en plus sinon ça voudrait dire qu'on pourrait modifier une appli après qu'elle a été validée par les lutins de l'AppStore, donc comment Apple pourrait savoir que tu la modifies pas pour rajouter des trucs interdits par Apple ?)
  • muqaddarmuqaddar Administrateur
    12:44 modifié #21
    Ok, je te suis à  100% sur ton raisonnement.
    Merci l'artiste du code.
  • Fallout88Fallout88 Membre
    12:44 modifié #22
    Moi je serai plus dans l'à®dée de faire une synchronisation des deux bases par webService. Bon sur le même principe qu'AliGator pour la détection de MaJ mais je ne récuperais que les enregistrements à  ajouter à  la base de l'iPhone pour ne pas à  avoir à  retélécharger toute la base à  chaque mise à  jour (je pense aux connexions Edge, comme moi v_v). Mais bon après faut pas oublier que le fichier SQLITE3 va pas peser bien lourd mais quand même faut voir selon le genre d'appli que tu veux mettre en place.
    Et pour le plus couteux je suis pas sûr que cela revienne bien cher, un simple hébergement de quelques Mo suffira tant qu'il gére le PhP et pas besoin de MySQL il existe des classes pour intéragir avec SQLite. 
  • muqaddarmuqaddar Administrateur
    12:44 modifié #23
    Attention, je parlais de plus couteux en temps, pas en argent... ;-)

    L'inconvénient de ta solution, c'est que si je modifie un enregistrement existant, ça ne va pas télécharger la base entière.

    Alors, bien sûr, on pourrait imaginer ajouter un flag sur la BDD (mise à  jour ou fichier entier), mais là  je crois que pour une base de 50 ou 100 Ko, ça ne vaut pas la peine de s'embêter, surtout que les MAJ depuis l'appli risquent d'être manuelles (ou alors en réglage dans une pref).
  • Fallout88Fallout88 Membre
    12:44 modifié #24
    C'est sûr pour un fichier de 100ko, mieux vaut ne pas ce prendre la tête alors.
  • muqaddarmuqaddar Administrateur
    septembre 2009 modifié #25
    Je relance mon sujet.  <3 <br />
    J'ai établi mes schémas et mes tables SQL.
    Si je laisse tout sur l'iPhone, en local donc, je n'ai pas de problème.

    Ma question porte sur la synchronisation iPhone => serveur.

    Sur l'iPhone, j'ai une table A, que l'utilisateur va remplir (id en auto-increment).
    Et donc chaque utilisateur va faire la même chose.

    Si j'opte pour une solution de synchronisation de leur base sur serveur (pour 2 raisons : ça leur fait une backup, et p-e qu'on peut envisager un site communautaire dans le futur...), je ne peux gérer cela dans la même table A sur le serveur, car des IDs auront la même valeur (forcément puisqu'on récupère tous les Users qui ont fait leur cuisine).

    On peut donc imaginer une table Users, avec gestion de compte User (classique) ET une table C qui contiendrait (id, user_id, et local_id). Ce local_id, vous l'avez compris, ce serait l'id que l'on trouve dans les tables A de chaque User.

    1) Avez-vous mieux comme solution ?

    2) Pour la synchronisation, autant je sais ouvrir des compte via NSURLConnection en envoyant un login et un password, autant je me demande comment envoyer des infos qui contiennent 50 enregistrements à  ajouter dans une table (et même plusieurs tables en relation) ? Et plus tard à  récupérer ou synchroniser les infos...
  • muqaddarmuqaddar Administrateur
    12:44 modifié #26
    J'ai trouvé ceci sur un site américain :

    The Client Side Application:
    1) receive input from the user (or client app event)
    2) generate SQL request
    3) XML encode the request if necessary
    4) pass the request to the web service

    The Server Side application:
    1) receive request
    2) decode (XML parse) the input if necessary
    3) analyze the request
    4) perform the DB query
    5) XML encode the query results
    6) return the results

    The Client Side application:
    1) receive results
    2) decode (XML parse) the results if necessary
    3) analyze the results if necessary
    4) generate DB query to update client DB if necessary
    5) perform the DB query to update client DB if necessary
    6) display results if necessary

    Given: that you have access to (or can write) a web service that functions as described above.

    Your iPhone app would likely include:
    1) an http interface to access the web service
    2) an XML parser
    3) an XML encoder
    4) an SQLite DB interface

    Whew!


    Je ne sais pas si il y a mieux, que l'échange des données en XML qui génèrent du SQL de chaque côté (client, server).

  • Fallout88Fallout88 Membre
    12:44 modifié #27
    Moi perso j'utiliserais un service Web (coté serveur) en utilisant REST pour la communication mais je ne passerais pas de SQL dans la requête comme dit le site ricain. Ainsi, si tu dois changer de base ou de structure de table tu t'en fiches car c'est le serveur qui génère la requête SQL. Et tu pourras bien sûr envoyer tout tes enregistrements dans la même requête.

    On peut donc imaginer une table Users, avec gestion de compte User (classique) ET une table C qui contiendrait (id, user_id, et local_id). Ce local_id, vous l'avez compris, ce serait l'id que l'on trouve dans les tables A de chaque User.

    Tu parles de la base sur le serveur ou sur l'iPhone?
  • muqaddarmuqaddar Administrateur
    12:44 modifié #28
    dans 1251895939:

    Moi perso j'utiliserais un service Web (coté serveur) en utilisant REST pour la communication mais je ne passerais pas de SQL dans la requête comme dit le site ricain. Ainsi, si tu dois changer de base ou de structure de table tu t'en fiches car c'est le serveur qui génère la requête SQL. Et tu pourras bien sûr envoyer tout tes enregistrements dans la même requête.

    On peut donc imaginer une table Users, avec gestion de compte User (classique) ET une table C qui contiendrait (id, user_id, et local_id). Ce local_id, vous l'avez compris, ce serait l'id que l'on trouve dans les tables A de chaque User.

    Tu parles de la base sur le serveur ou sur l'iPhone?


    Sur le serveur.

    Je ne compte pas envoyer de requêtes SQL mais du XML + une URL qui parse le XML et le transforme en requête SQL (effectivement, ça serait du REST sur le serveur).
Connectez-vous ou Inscrivez-vous pour répondre.