Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème consommation serveur

Optimisation SQL / JAVA - Problème

    19 mai 2019 à 12:37:37

    Bonjour à tous, je dispose d'un serveur, qui charge dès le lancement énormément de donnée. Le problème actuel se pose sur une table, qui coute 3 Go à la RAM pour la charger et stocker. Cela pose problème parce que je ne peux même plus charger cette base de donnée sur mon PC.

    Actuellement le nombre d'entrées de la table est de : 3 236 000 et pèse 252 MB.

    Voici la table en question :

     Target Server Type    : MySQL
     Target Server Version : 100138
     File Encoding         : 65001
    
     Date: 19/05/2019 12:32:11
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for items
    -- ----------------------------
    DROP TABLE IF EXISTS `items`;
    CREATE TABLE `items` (
      `id` int(11) NOT NULL,
      `template` int(11) NOT NULL,
      `qua` int(11) NOT NULL,
      `pos` int(11) NOT NULL,
      `stats` text NOT NULL,
      `runes` text,
      PRIMARY KEY (`guid`) USING BTREE,
      UNIQUE KEY `guid` (`guid`) USING BTREE
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
    
    SET FOREIGN_KEY_CHECKS = 1;

    Voici maintenant les variables de la class "Item" :

    	private int id = 0, qua = 0, pos = 0;
    	private ItemTemplate template = null;
    	private String stats = "";
    	private Map<Integer,List<String>> otherStats = new LinkedHashMap<Integer,List<String>>();
    	private static Map<Integer, Item> cache = new HashMap<Integer, Item>();
    	private static int objectIdIndex = 0;
    	private List<EffectManager> effects = new ArrayList<EffectManager>();
    	private List<EffectManager> cCeffect = new ArrayList<EffectManager>();


    A savoir : La liste "cache" me permet de stocker toutes les entrées et de pouvoir les récupérer au fur et à mesure après.

    La liste otherStats contient d'autres statistiques sur l'item, j'ai utilisé un LinkedHashMap parce que je veux que l'ordre d'affichage soit dans l'ordre d'ajout.

    En espérant que vous allez pouvoir m'aiguiller sur des potentiels façon d'optimiser tout ça afin de rendre le chargement beaucoup plus viable.

    Bonne journée et merci :)

    • Partager sur Facebook
    • Partager sur Twitter
      19 mai 2019 à 18:41:39

      Bonjour,

      Qu'entendez vous par "La liste "cache" me permet de stocker toutes les entrées et de pouvoir les récupérer au fur et à mesure après.".

      Si vous récupérez tous le contenu de la base la table items en base de donnée dans cette liste, c'est normal que vous ayez des problèmes de mémoire, il ne faut pas faire cela.
      Quand on travaille avec une base de donnée relationnelle, il ne faut pas récupérer tout le contenu de la base de donnée dans des variables côté java pour pouvoir travailler dessus.
      Il ne faut récupérer côté java que les données que vous voulez afficher ou modifier.
      Si vous avez regardé des exemples de code jpa, vous avez sans doute vu des méthodes "findAll" même il ne faut utiliser ce genre de méthode que sur des petites tables (et encore en général on en a pas besoin).

      • Partager sur Facebook
      • Partager sur Twitter
        19 mai 2019 à 22:27:45

        Merci pour votre réponse. En effet quand cette liste me permet de récupérer grâce à l'ID n'importe quand la class associé. J'ai effectué des test en local en supprimant l'ajout dans la liste etc. La consommation vient de la création de 3M2 class associés, du coup malheureusement je n'ai pas l'impression que je peux faire grand chose hors mis charger dynamiquement ce dont j'ai besoin, mais la c'est une peur des performances que j'ai de devoir faire des requêtes très régulière.


        macaque a écrit:

        Bonjour,

        Qu'entendez vous par "La liste "cache" me permet de stocker toutes les entrées et de pouvoir les récupérer au fur et à mesure après.".

        Si vous récupérez tous le contenu de la base la table items en base de donnée dans cette liste, c'est normal que vous ayez des problèmes de mémoire, il ne faut pas faire cela.
        Quand on travaille avec une base de donnée relationnelle, il ne faut pas récupérer tout le contenu de la base de donnée dans des variables côté java pour pouvoir travailler dessus.
        Il ne faut récupérer côté java que les données que vous voulez afficher ou modifier.
        Si vous avez regardé des exemples de code jpa, vous avez sans doute vu des méthodes "findAll" même il ne faut utiliser ce genre de méthode que sur des petites tables (et encore en général on en a pas besoin).

        -
        Edité par reben 19 mai 2019 à 22:28:52

        • Partager sur Facebook
        • Partager sur Twitter
          20 mai 2019 à 17:42:07

          Le principe d'une base de donnée c'est bien de récupérer dynamiquement les données dont on a besoin sans récupérer toute la table.
          Si vous récupérer tout la table, modifier un truc et repoussez toute la table, ça n'a pas d’intérêt de le faire un SQL, autant utiliser la sérialisation java.
          Si votre table sql est indexée sur les "id" que vous recherchez, les requêtes devrait être très rapide.
          De plus les implémentations jpa gère le plus souvent elle même un cache pour ne pas récupérer en base ce qu'elles viennent de re-récupérer, et elles optimisent également les moments où les données sont poussées vers la base de donnée.
          Il faut que vous utilisiez la méthode "find" de l'entity manager pour récupérer les entrées de votre table par leur id (https://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html).

          Après si vous avez vraiment des boucles qui tournent sur toutes votre table, là il faut peut être soit remplacer ces boucles par des requêtes SQL, soit faire complètement autrement et ne pas utiliser SQL.


          • Partager sur Facebook
          • Partager sur Twitter
            20 mai 2019 à 23:31:19

            D'accord merci beaucoup pour votre message, dernière question, faire énormément de requête pour récupérer des informations n'est pas trop lourd pour les performances ? J'ai peur qu'utiliser énormément de requête pour récupérer des données à la volé rende mon application moins performante étant donné qu'actuellement je ne fais aucune requête SQL, les INSERT,UPDATE,DELETE sont mises en cache pour être exécuté toute d'un coup à des intervalles de 2 heures.


            macaque a écrit:

            Le principe d'une base de donnée c'est bien de récupérer dynamiquement les données dont on a besoin sans récupérer toute la table.
            Si vous récupérer tout la table, modifier un truc et repoussez toute la table, ça n'a pas d’intérêt de le faire un SQL, autant utiliser la sérialisation java.
            Si votre table sql est indexée sur les "id" que vous recherchez, les requêtes devrait être très rapide.
            De plus les implémentations jpa gère le plus souvent elle même un cache pour ne pas récupérer en base ce qu'elles viennent de re-récupérer, et elles optimisent également les moments où les données sont poussées vers la base de donnée.
            Il faut que vous utilisiez la méthode "find" de l'entity manager pour récupérer les entrées de votre table par leur id (https://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html).

            Après si vous avez vraiment des boucles qui tournent sur toutes votre table, là il faut peut être soit remplacer ces boucles par des requêtes SQL, soit faire complètement autrement et ne pas utiliser SQL.




            • Partager sur Facebook
            • Partager sur Twitter
              23 mai 2019 à 18:29:47

              Je ne sais pas vraiment ce que vous appelez "énormément" donc c'est difficile de répondre précisément mais une base de donnée est bien faite pou gérer beaucoup de requêtes, et en plus la couche "jpa" gère un cache de manière intelligente justement pour diminuer ce nombre de requête.
              Une bonne base avec des requêtes optimisées peut sans doute gérer plusieurs centaines de requêtes par secondes voir plus.

              Mettre des requêtes SQL en cache pour les exécuter toute d'un coup à intervalles de 2 heures me semble en tout cas une très mauvaise idée.
              On perd tout l'intérêt de la base de donnée (intégrité des données, transaction, etc) pour au final si je comprends bien exécuter les requêtes dessus au but de 2 heures ?

              Cela signifie que si votre application plante avant les 2 heures toutes les informations sont perdues ?
              De même si jamais une des requêtes SQL dans le cache génère une erreur quand vous essayez de mettre à jour la base au bout de 2 heures, que ce faite vous des requêtes suivantes, comment garantissez vous l'état de la base de donnée.
              De plus cela signifie que votre solution n'est pas scalable, vous ne pouvez pas avoir deux instances qui exécutent les traitements en parallèle car les deux vont travailler avec un cache de donnée différent et vous allez avoir des soucis de concurrence lorsque vous allez essayer de mettre à jour votre base de donnée.

              Ce qui est une mauvaise idée également c'est de faire des requêtes SQL "à la main" sans passer par une couche jpa avec par exemple hibernate ou eclipseLink.

              Faites également attention à la gestion de vos transactions pour qu'elle soit le plus courte possible toute en étant suffisamment atomique par rapport à intégrité de la base de donnée.

              Si la base de donnée relationnel ne vous semble pas adapté pour ce pour quoi vous voulez faire, regarder du côté d'une base de donnée nosql mais ne gérer pas un cache à la main avec toutes les infos en mémoire volatile par dessus la base mysql.

              D'une manière générale, si les choix architecturaux initiaux sont importants pour les performances futures, essayer de faire des optimisations "à la main" avec sa propre solution sans avoir vraiment rencontrer le problème de perf est généralement la meilleure façon d'avoir des problèmes.

              Ce que je vous conseillerais d'après les informations que j'ai :

              - Réfléchissez à vos besoins concernant vos données :
              Est-ce que l'intégrité des données stockée est important ?
              Est-ce qu'elles pourront tenir dans la mémoire vive toutes en même temps ?
              Est-ce que vous pouvez vous permettre de perdre des données déjà traitées ?
              Est-ce que plusieurs "applications" peuvent avoir besoin d'accéder aux données en même temps ?
              Est-ce que vous accédez toujours à vos données avec une clef simple ou est-ce que parfois vous avez besoin de sélectionner des données de manière plus spécifique (du genre les entrées entre telle et telle date, ou dont la colonne A vaut X et la colonne B est null ou entre 45 et 60 ?)

              - Essayer dans tous les cas de faire une application ou la gestion des données est bien découpée du reste, avec des méthodes pour récupérer les données strictement nécessaire au traitement à partir d'information bien identifiée (comme les id) et les mettre à jour.
              Cela vous permettra de plus facilement changer la couche de gestion des données.

               - Implémenter ces méthodes avec une base de donnée et une couche jpa (hibernate ou eclipse link).
               - Faites des tests de performances
               - Si vous avez des soucis de perf, essayer de les comprendre, de voir si c'est facilement réglable (en rajoutant un index sur une table ou en configurant le cache un peu mieux) ou si c'est vraiment plus profond. Au moins vous saurez alors quel est le problème à résoudre et pourquoi vous choisissez une autre solution.

              • Partager sur Facebook
              • Partager sur Twitter

              Problème consommation serveur

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown