Optimisation d'une requête SVP

Bonjour,

J'ai une requête qui mets bcp de temps, je n'arrive vraiment pas à l'optimiser.

Deux table sont concernées, Membere + Tchat message

Le but est de recevoir toutes les lignes du tchat avec le pseudo de chaque membre sur le côté, pour ce faire, y a plusieurs requetes, mais la plus importante est celle ci :
$sql = "SELECT * FROM (
      SELECT DISTINCT t2.pseudo, t2.id as id, t1.send FROM `chat_messages` t1,         `member` t2
      WHERE
      (
         (t1.`sender_id` = ".$_POST['user']." AND t1.`status` != 1 AND t1.`receiver_id` = t2.`id`)
           OR
         (t1.`receiver_id` = ".$_POST['user']." AND t1.`status` != 2 AND t1.`sender_id` = t2.`id`)
      )
   ORDER BY t1.`send` desc) C GROUP BY `pseudo` ORDER BY send DESC";

$request = mysql_query($sql);


Je ne sais pas si vous pouvez m'aider sans connaitre le besoin, mais au moins si vous avez une idée de jointure par exemple qui peut oprimiser ;)

Merci bcp par avance de votre aide.

Au plaisir de vous lire.

Cdt

EDIT : Ajout des balilses de code

3 réponses

  1. Bonjour,

    As-tu défini des index sur chat_message ?
    À mon avis c'est la première étape.
    Un index sur chat_message.sender_id, et un sur chat_message.receiver_id.

    Par ailleurs, je ne suis pas sûr de comprendre l'intérêt de ton GROUP BY sachant qu'il n'y a aucune fonction d'agrégation dans ton résultat.

    Tu peux montrer un exemple du résultat que tu attends ?

    Xavier
    1. Modérateur
      Bonjour,

      Plusieurs petites choses...
      - Tu injectes directement une variable POST ... sans avoir au préalable vérifier qu'elle existait.
      - Je pense qu' une jointure serait plus adaptée ....

      N'ayant pas la structure de tes tables je ne peux pas tester.. .mais quelque chose de ce genre devrait faire l'affaire.
      $user = isset($_POST['user'])?$_POST['user']:NULL;
      if($user){
      $sql = "SELECT DISTINCT M.pseudo
                      , M.id as id
                      , CM.send 
              FROM `chat_messages` CM
              LEFT JOIN `member` M ON ((M.id=CM.sender_id OR M.id=CM.receiver_id) AND CM.`status` != 1)
              GROUP BY pseudo 
              ORDER BY send DESC";
      
      $request = mysql_query($sql) or die("erreur !<br>".$sql);
      
      
      }
      


      Cordialement,
      Jordane
      1. Bonjour à vous et merci pour votre aide,
        Tout d'abord, pour les index sur chat_message.sender_id, et un sur chat_message.receiver_id. c'est déjà fait.

        Le group by c'est pour regrouper en fonction des dates les plus recentes (send est un champ date)

        Voici ci joint le réssultat attendu


        Jordane, merci bcp, voici la structure des deux tables:

        chat_message:
        CREATE TABLE IF NOT EXISTS `chat_messages` (
          `id` int(11) NOT NULL AUTO_INCREMENT,
          `sender_id` int(11) NOT NULL,
          `receiver_id` int(11) NOT NULL,
          `message` text COLLATE utf8_unicode_ci NOT NULL,
          `send` datetime NOT NULL,
          `read` int(11) NOT NULL,
          `status` int(11) NOT NULL,
          PRIMARY KEY (`id`),
          KEY `IDX_received` (`receiver_id`),
          KEY `IDX_sender` (`sender_id`)
        ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=303054 ;
        


        et pour membre
        CREATE TABLE IF NOT EXISTS `member` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `pseudo` varchar(15) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `first_name` varchar(255) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `last_name` varchar(255) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `email` varchar(255) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `temp_email` varchar(255) COLLATE latin1_general_ci DEFAULT NULL,
          `password` varchar(40) COLLATE latin1_general_ci NOT NULL,
           `postcode` varchar(10) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `city` varchar(255) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          `country` int(11) unsigned DEFAULT NULL,
          `region` int(11) unsigned DEFAULT NULL,
          `department` int(11) unsigned DEFAULT NULL,
            `type` tinyint(4) unsigned NOT NULL DEFAULT '0',
          `date_of_birth` date NOT NULL DEFAULT '0000-00-00',
          `birth_sign` int(11) DEFAULT NULL,
          `my_search` int(11) unsigned NOT NULL DEFAULT '0',
          `type_of_meeting` varchar(45) COLLATE latin1_general_ci NOT NULL DEFAULT '',
          
          PRIMARY KEY (`id`),
          UNIQUE KEY `uniic_member_pseudo` (`pseudo`)
        ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=21959 ;
        


        je suis d'accord, je pense qu'il faudrait une jointure mais je suis bloqué j'arrive plus :(

        Merci énormément de votre aide

        EDIT : Ajout des balises de code
        1. jordane, oui je l'ai modifié en ajoutant la partie status et pour le moment, ta requête fait bcp de bien :), je l'utilise du coup en attendant optimiser encore plus si possible, sinon je la garde :):)

          Merci bcp Jordane, tu m'a rendu un grand service :)
        2. Modérateur
          @ko3arBen la. .. je ne vois pas comment tu pourrais plus l'optimiser. ..
        3. Bonjour Jordane45
          En fait, c'est vrai qu'on peut pas faire mieux, mais ce qu'il me gène un peu, c'est que quand je mets un Explain, j'ai ce message :
          Range checked for each record (index map: 0x1)

          et j'ai vu que ce n'est pas top en terme de performance
          vous en pensez quoi ?

          Merci beaucoup de votre conseil