Jump to content

Problème lenteur quand j'active mon module.


Recommended Posts

Bonjour !

Je viens de finaliser un module assez simple qui regroupe l'emplacement de stock de mes produits en fonction de leurs références.

Le module fonctionne très bien en local, mais quand je le passe sur le serveur et que j'ajoutes mon CSV sur la BDD directement avec 2365 entrées, le site ce met à ralentir fortement, pourtant le module génère pour moi peu de ressource... Alors peut être que dans mon AdminController je fais quelque chose de mal ? J'ai trouvé aucun moyen de savoir d'ou vient l'erreur. le DEBUG ne m'affiche rien.

 

Voici quelques ressources de mon module :

Mon AdminController :

lass AdminSweetchEmplacementsController extends ModuleAdminController {
    
    // Changement pagination
    protected $_default_pagination = 10;

	public function __construct(){
        
        // Variable
        $this->table = 'sweetchemplacement';
        $this->className = 'SweetchEmplacement';
        $this->bulk_actions = array(
            'delete' => array(
                'text'    => 'Supprimer ?',
                'confirm' => 'Sur ?'
            )
        );

        parent::__construct();

        // Nom du produit
         $this->_select  = 'pa.`id_product` as id_product, pl.`name` as product_name';
        $this->_join     = 'LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (pa.`reference` = a.`product_reference`) 
                            LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (pl.`id_product` = pa.`id_product` AND pl.`id_lang` = 1)';
        $this->_group    = 'GROUP BY a.`id_sweetchemplacement`';
        $this->_defaultOrderBy = 'emplacement';
        $this->_orderWay = 'DESC'; 

        $this->fields_list['product_reference'] = array(
            'title' => 'ID Référence',
            'align' => 'left',
            'width' => 100
        );

         $this->fields_list['product_name'] = array(
            'title'  => 'Nom du produit',
            'align'  => 'left',
            'width'  => 200,
            'search' => true,
            'filter_key' => 'pl!name',
        ); 


        $this->fields_list['emplacement'] = array(
            'title' => 'Emplacement stock',
            'align' => 'left',
            'width' => 100,
            'search' => true
        );


        $this->bootstrap = true;

        $this->meta_title = 'Sweetch Emplacement';

	}

    public function renderList() {

        $this->addRowAction('edit');
        $this->addRowAction('view');
        $this->addRowAction('delete');
        
        return parent::renderList();
    }

    public function renderView(){

        $tpl = $this->context->smarty->createTemplate(dirname(__FILE__).'/../../views/templates/admin/view.tpl');
        $tpl->assign('sweetchemplacement', $this->object);
        return $tpl->fetch();
    }


    public function renderForm(){

        $this->context = Context::getContext();
        $this->context->controller = $this;
        $this->fields_form = array(
            'legend' => array(
                'title' => 'Créer ou Modifier un emplacement'
            ),
            'input' => array(

                array(
                    'type'  => 'text',
                    'label' => 'Référence du produit',
                    'name'  => 'product_reference',
                    'desc'  => 'Doit être un numéro flotant'
                ),

                array(
                    'type' => 'text',
                    'label' => 'Emplacement Stock',
                    'desc' => 'Doit être un numéro flotant',
                    'name' => 'emplacement',
                ),
            ),

            'submit' => array('title' => 'Sauvegarder')
        );

        return parent::renderForm();
    }


}

Mon fichier core module

class SweetchEmplacements extends Module
{
	public function __construct(){

		// Name & Description
		$this->name = 'sweetchemplacements';
		$this->author = 'Sweetch';
		$this->version = '1.0.0';
		$this->bootstrap = true;

		$this->displayName = $this->l('Sweetch WareHouse');
		$this->description = $this->l('Warehouse product for company');

        parent::__construct();		
	}

	public function getContent(){
	    return $this->display(__FILE__, 'getContent.tpl');
	}


    // Install
	public function install(){

        if (!parent::install()) {
        	return false;
        }

        if (!$this->installDB()) {
        	return false;
        }

        if (!$this->installTab('AdminCatalog','AdminSweetchEmplacements', 'Sweetch Emplacement')) {
        	return false;
        }

        return true;
	}
    
    // Uninstall
	public function uninstall(){

        if (!parent::uninstall()) {
        	return false;
        }

        if (!$this->uninstallDB()) {
        	return false;
        }

        if (!$this->uninstallTab('AdminSweetchEmplacements')) {
        	return false;
        }

        return true;
	}

	public function installDB(){

		return (
			Db::getInstance()->Execute('
			CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'sweetchemplacement` (
					`id_sweetchemplacement` int(10) NOT NULL AUTO_INCREMENT,
					`product_reference` varchar(255) NOT NULL,
					`emplacement` float(10) NOT NULL DEFAULT 0,
					`date_add` datetime NOT NULL,
					PRIMARY KEY (`id_sweetchemplacement`)
			) ENGINE = '._MYSQL_ENGINE_.' DEFAULT CHARSET=UTF8;')
		);
	}

	public function uninstallDB(){

		return (
        Db::getInstance()->Execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'sweetchemplacement`')
		);
	}

	public function installTab($parent, $class_name, $name){

		$tab =  new Tab();
        $tab->id_parent = (int)Tab::getIdFromClassName($parent);
        $tab->name = array();
        foreach (Language::getLanguages(true) as $lang) {
        	$tab->name[$lang['id_lang']] = $name;
        }
        $tab->class_name = $class_name;
        $tab->module = $this->name;
        $tab->active = 1;

        return $tab->add();
	}

	public function uninstallTab($class_name){

        $id_tab = (int)Tab::getIdFromClassName($class_name);
        $tab = new Tab((int)$id_tab);

        return $tab->delete();
	}

}

Merci pour vos futurs indications... !

Link to comment
Share on other sites

Le forum n'est pas l'endroit le plus pratique pour commenter du code...

Le problème vient plutôt de votre requête SQL en fait.

Du coup, pour rendre le code un peu plus lisible, je te propose dans un premier temps une version épurée, n'hésite pas à poser des questions.

Module (modules/sweetchemplacements/sweetchemplacements.php) :

<?php

if (!defined('_PS_VERSION_')) {
    exit;
}

require_once __DIR__ . '/classes/SweetchEmplacement.php';

class SweetchEmplacements extends Module
{
    /**
     * Name of your ModuleAdminController
     */
    const MODULE_ADMIN_CONTROLLER = 'AdminSweetchEmplacements';

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->name = 'sweetchemplacements';
        $this->tab = 'administration';
        $this->version = '1.0.0';
        $this->author = 'Sweetch';
        $this->need_instance = 0;

        parent::__construct();

        // Must be placed after call to parent because translator must be initialized for next lines
        $this->displayName = $this->l('Sweetch WareHouse');
        $this->description = $this->l('Warehouse product for company');
    }

    /**
     * Install Module
     *
     * @return bool
     */
    public function install()
    {
        return parent::install()
            && $this->installDB()
            && $this->installTabs();
    }

    /**
     * Install database
     *
     * @return bool
     */
    public function installDB()
    {
        return Db::getInstance()->execute('
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'sweetchemplacement` (
            `id_sweetchemplacement` int(10) unsigned NOT NULL AUTO_INCREMENT,
            `product_reference` varchar(255) NOT NULL,
            `emplacement` float(10) NOT NULL DEFAULT 0,
            `date_add` datetime NOT NULL,
            PRIMARY KEY (`id_sweetchemplacement`)
            ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;');
    }

    /**
     * Install Tabs
     *
     * @return bool
     */
    public function installTabs()
    {
        if (Tab::getIdFromClassName(static::MODULE_ADMIN_CONTROLLER)) {
            return true;
        }

        $tab = new Tab();
        $tab->class_name = static::MODULE_ADMIN_CONTROLLER;
        $tab->module = $this->name;
        $tab->active = true;
        $tab->id_parent = -1;
        $tab->name = array_fill_keys(
            Language::getIDs(false),
            $this->displayName
        );

        return $tab->add();
    }

    /**
     * Uninstall Module
     *
     * @return bool
     */
    public function uninstall()
    {
        return parent::uninstall()
            && $this->uninstallDB()
            && $this->uninstallTabs();
    }

    /**
     * Uninstall database
     *
     * @return bool
     */
    public function uninstallDB()
    {
        return Db::getInstance()->execute('DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'sweetchemplacement`');
    }

    /**
     * Uninstall Tabs
     *
     * @return bool
     */
    public function uninstallTabs()
    {
        $id_tab = (int) Tab::getIdFromClassName(static::MODULE_ADMIN_CONTROLLER);

        if ($id_tab) {
            $tab = new Tab($id_tab);
            return $tab->delete();
        }

        return true;
    }

    /**
     * Redirect to your ModuleAdminController when click on Configure button
     */
    public function getContent()
    {
        Tools::redirectAdmin($this->context->link->getAdminLink(static::MODULE_ADMIN_CONTROLLER));
    }
}

ObjectModel (modules/sweetchemplacements/classes/SweetchEmplacement.php) :

<?php

class SweetchEmplacement extends ObjectModel
{
    /**
     * @var string
     */
    public $product_reference;

    /**
     * @var float
     */
    public $emplacement;

    /**
     * @var string
     */
    public $date_add;

    public static $definition = array(
        'table' => 'sweetchemplacement',
        'primary' => 'id_sweetchemplacement',
        'multilang' => false,
        'fields' => array(
            'product_reference' => array('type' => self::TYPE_STRING, 'validate' => 'isReference', 'size' => 255),
            'emplacement' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
            'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
        ),
    );
}

ModuleAdminController : (modules/sweetchemplacements/controllers/admin/AdminSweetchEmplacementsController.php)

<?php

class AdminSweetchEmplacementsController extends ModuleAdminController
{
    public function __construct()
    {
        $this->table = 'sweetchemplacement';
        $this->className = 'SweetchEmplacement';
        $this->bootstrap = true;
        $this->addRowAction('edit');
        $this->addRowAction('delete');

        parent::__construct();

        // Problem is here, your query is not good
        $this->_select = 'pa.`id_product` as id_product, pl.`name` as product_name';
        $this->_join = 'LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pa.`reference` = a.`product_reference`)';
        $this->_join .= 'LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (pl.`id_product` = pa.`id_product` AND pl.`id_lang` = ' . (int) $this->context->language->id . ')';
        $this->_group = 'GROUP BY a.`reference`'; // Not right choice
        $this->_defaultOrderBy = 'emplacement';
        $this->_orderWay = 'DESC';
        $this->_default_pagination = 10;

        // Here, if you would use Translator, this lines must be after call to parent because translator must be initialized
        $this->meta_title = 'Sweetch Emplacement';

        $this->bulk_actions = array(
            'delete' => array(
                'text' => 'Supprimer ?',
                'confirm' => 'Sur ?',
            ),
        );

        $this->fields_list = array(
            'product_reference' => array(
                'title' => 'ID Référence',
                'align' => 'left',
                'width' => 100,
            ),
            'product_name' => array(
                'title' => 'Nom du produit',
                'align' => 'left',
                'width' => 200,
                'search' => true,
                'filter_key' => 'pl!name',
            ),
            'emplacement' => array(
                'title' => 'Emplacement stock',
                'align' => 'left',
                'width' => 100,
                'search' => true,
            ),
        );

        $this->fields_form = array(
            'legend' => array(
                'title' => 'Créer ou Modifier un emplacement',
            ),
            'input' => array(
                array(
                    'type' => 'text',
                    'label' => 'Référence du produit',
                    'name' => 'product_reference',
                    'desc' => 'Doit être un numéro flotant',
                ),
                array(
                    'type' => 'text',
                    'label' => 'Emplacement Stock',
                    'desc' => 'Doit être un numéro flotant',
                    'name' => 'emplacement',
                ),
            ),
            'submit' => array('title' => 'Sauvegarder'),
        );
    }
}

Le module fonctionne mais ce n'est pas l'idéal car la requête SQL générée est pas top

Quote

#1055 - Expression #5 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'prestashop.pa.id_product' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

Bref le point d'amélioration est à faire ici, il vaut mieux se baser sur des ID que sur des références pour faire des jointures.

Donc revoir la partie base de données, structure de la table, identifiants pour les jointures etc...

Edited by Janett (see edit history)
Link to comment
Share on other sites

Alors déjà un grand merci pour cette re-structuration plus pro du module.

Deuxième point, si je comprend bien ce qui fâche c'est

$this->_group = 'GROUP BY a.`reference`'; // Not right choice

et puis surement ceci 

$this->_join = 'LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pa.`reference` = a.`product_reference`)';

car je fais un lien avec un varchar et ceci être peut-être lié au problème ?

 

Comment-avez eu cette aide ? 

#1055 - Expression #5 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'prestashop.pa.id_product' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

 

Et comment puis-je savoir si la requête est bonne ? car son localhost mon site ne plante pas... 

 

Merci beaucoup.

Link to comment
Share on other sites

36931595_Capturedecran2019-05-22a17_13_21.thumb.png.2be2efbabb68963064894ccff70896df.png

En cliquant sur l'icône dans le carré rouge, la requête SQL générée s'affiche. Il vous suffit de tenter de l'exécuter dans phpmyadmin par exemple.

Ce n'est pas spécialement le fait que ce soit un varchar dans la jointure, le problème c'est surtout que sans le group by, la requête vous renvoie plusieurs résultats pour 1 seul produit, ce qui implique que votre jointure n'est pas suffisamment précise. Normalement il n'y a pas besoin de group by dans votre cas, si la requête est bien construite.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...