IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes MySQL Discussion :

Performances d'une requête complexe incluant recherche fulltext


Sujet :

Requêtes MySQL

  1. #1
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut Performances d'une requête complexe incluant recherche fulltext
    Salut,

    Je dois permettre à un utilisateur de chercher des articles qui sont liés à certains tags qu'il peut choisir pour filter.

    Et il doit aussi pouvoir entrer des mot-clés pour une recherche full text.

    Et il peut définir des groupes de filtres afin de gérer des AND et OR. Au sein d'un groupe les critères sont OR tandis que entre les groupes c'est AND. Ca pourrait donner quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    filter_group1 : (
      (tag1(123) OR tag2(234))
      OR
      (keyword1 OR keyword2)
    )
    AND
    filter_group2 : (
      (tag3(345))
      OR
      (keyword3 OR keyword4)
    )
    L'association entre les articles et les tags se fait avec une table du genre term_node( tag_id, article_id ).

    La table article a un champ title et un champ body sur lesquels j'ai créé un index FULLTEXT(title, body).

    Il est susceptible d'y avoir entre 1 et 6 groupes de filtres. Et il peut exister 1 million d'articles.

    La requête est construite en partie dynamiquement en PHP et ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    SELECT
    	node.nid AS article_id,
    	node.title AS article_title,
    	node.body AS article_body
    FROM
    	node
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    	(
    		(tn1.tid IN (123, 234))
    		OR
    		(MATCH(node.title, node.body) AGAINST ('keyword1 keyword2' IN BOOLEAN MODE))
    	)
    	AND (
    		(tn2.tid IN (345))
    		OR
    		(MATCH(node.title, node.body) AGAINST ('keyword3 keyword4' IN BOOLEAN MODE))
    	)
    Est-ce que de telles requêtes ont une chance d'être suffisamment performantes vu la taille du dataset et les jointures ? Sachant que je vais aussi devoir trier ?

    Merci d'avance

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Si les nid et tid sont tous indexés, ça ne devrait pas poser de problème.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Si les nid et tid sont tous indexés, ça ne devrait pas poser de problème.
    Merci. J'ai vérifié, ils sont indexés mais ça prend quand même plus de 80 secondes à exécuter la requête alors que je n'ai que 40'000 lignes dans la table node et que l'écrasante majorité des body fait moins de 10'000 signes (il y en a quatre qui font entre 100'000 et 400'000).

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    On peut avoir la structure exacte des tables ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    On peut avoir la structure exacte des tables ?
    J'avais essayé de simplifier pour rester au niveau du concept, mais oui, bien volontiers.

    Petite complexité, il y a en fait deux tables : node qui est la table principale et node_revisions qui contient les différentes versions de title et body d'un node.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    CREATE TABLE `node` (
      `nid` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `vid` int(10) unsigned NOT NULL DEFAULT '0',
      `type` varchar(32) NOT NULL DEFAULT '',
      `language` varchar(12) NOT NULL DEFAULT '',
      `title` varchar(255) NOT NULL DEFAULT '',
      `uid` int(11) NOT NULL DEFAULT '0',
      `status` int(11) NOT NULL DEFAULT '1',
      `created` int(11) NOT NULL DEFAULT '0',
      `changed` int(11) NOT NULL DEFAULT '0',
      `comment` int(11) NOT NULL DEFAULT '0',
      `promote` int(11) NOT NULL DEFAULT '0',
      `moderate` int(11) NOT NULL DEFAULT '0',
      `sticky` int(11) NOT NULL DEFAULT '0',
      `tnid` int(10) unsigned NOT NULL DEFAULT '0',
      `translate` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`nid`),
      UNIQUE KEY `vid` (`vid`),
      KEY `node_changed` (`changed`),
      KEY `node_created` (`created`),
      KEY `node_moderate` (`moderate`),
      KEY `node_promote_status` (`promote`,`status`),
      KEY `node_status_type` (`status`,`type`,`nid`),
      KEY `node_title_type` (`title`,`type`(4)),
      KEY `node_type` (`type`(4)),
      KEY `uid` (`uid`),
      KEY `tnid` (`tnid`),
      KEY `translate` (`translate`)
    ) ENGINE=MyISAM AUTO_INCREMENT=105431 DEFAULT CHARSET=utf8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    CREATE TABLE `node_revisions` (
      `nid` int(10) unsigned NOT NULL DEFAULT '0',
      `vid` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `uid` int(11) NOT NULL DEFAULT '0',
      `title` varchar(255) NOT NULL DEFAULT '',
      `body` longtext NOT NULL,
      `teaser` longtext NOT NULL,
      `log` longtext NOT NULL,
      `timestamp` int(11) NOT NULL DEFAULT '0',
      `format` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`vid`),
      KEY `nid` (`nid`),
      KEY `uid` (`uid`),
      FULLTEXT KEY `keywords` (`title`,`body`)
    ) ENGINE=MyISAM AUTO_INCREMENT=105431 DEFAULT CHARSET=utf8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    CREATE TABLE `term_node` (
      `nid` int(10) unsigned NOT NULL DEFAULT '0',
      `vid` int(10) unsigned NOT NULL DEFAULT '0',
      `tid` int(10) unsigned NOT NULL DEFAULT '0',
      PRIMARY KEY (`tid`,`vid`),
      KEY `vid` (`vid`),
      KEY `nid` (`nid`),
      KEY `tid` (`tid`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CREATE TABLE `history` (
      `uid` int(11) NOT NULL DEFAULT '0',
      `nid` int(11) NOT NULL DEFAULT '0',
      `timestamp` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`uid`,`nid`),
      KEY `nid` (`nid`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    1 NOT IN (SELECT h.uid FROM history h WHERE h.nid = node.nid) /*pour ne pas proposer des articles déjà lu par l'utilisateur*/
    AND node.type = 'feed_item'
    AND node.status = 1 /*seulement les nodes "publiés"*/
    AND (
    	(tn1.tid IN (15937, 12628))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('keyword1 keyword2' IN BOOLEAN MODE))
    )
    AND (
    	(tn2.tid IN (3574))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('keyword3' IN BOOLEAN MODE))
    )
    GROUP BY node.nid
    ORDER BY node.nid DESC
    Merci beaucoup pour ton aide

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Dans ta requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MATCH(node.title, node.body)
    Or l'index FULLTEXT est sur la table 'node_revisions' !

    EDIT :
    La requête que tu donnes dans ton dernier message n'est pas la même que dans le premier !

    Ça ressemble à du Drupal ta structure !

    Plutôt que ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE
    1 NOT IN (SELECT h.uid FROM history h WHERE h.nid = node.nid) /*pour ne pas proposer des articles déjà lu par l'utilisateur*/
    Essaie plutôt ceci (si j'ai bien compris le système) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    WHERE NOT EXISTS
    (
      SELECT *
      FROM hitory h
      WHERE h.nid = node.nid
        AND h.uid = 1 -- C'est l'identifiant de l'utilisateur ?
    )
    Pourquoi un GROUP BY alors qu'il n'y a pas de fonction d'agrégation dans le SELECT ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Dans ta requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MATCH(node.title, node.body)
    Or l'index FULLTEXT est sur la table 'node_revisions' !

    EDIT :
    La requête que tu donnes dans ton dernier message n'est pas la même que dans le premier !
    Oui, je suis désolé pour la confusion, c'est parce que je voulais simplifier. C'est bien la 2ème requête qui la bonne et c'est bien celle-là que je teste.

    Ça ressemble à du Drupal ta structure !
    Oui, c'est du drupal.

  8. #8
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par lr Voir le message
    Oui, je suis désolé pour la confusion, c'est parce que je voulais simplifier. C'est bien la 2ème requête qui la bonne et c'est bien celle-là que je teste.
    J'ai édité et complété mon message après que tu as posté le tien.


    Oui, c'est du drupal.
    Et la fonction de recherche FULL TEXT de Drupal ne te suffit pas ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  9. #9
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    J'ai donc exécuté ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1 -- Oui, c'est bien l'identifiant de l'utilisateur
    )
    AND node.type = 'feed_item'
    AND node.status = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('keyword1 keyword2' IN BOOLEAN MODE))
    )
    AND (
    	(tn2.tid IN (3574))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('keyword3' IN BOOLEAN MODE))
    )
    ORDER BY node.nid DESC
    Et ça a pris 18 secondes. Il y a du mieux Mais ce n'est pas suffisant Sans la recherche full text, c'était très rapide.

    Je ne connais pas la fonction de recherche full text de Drupal 6. Tu penses que je pourrais faire ce que je veux de manière plus efficace avec ça ?

  10. #10
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Si je fais ça, ça prend 1 seconde :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.status = 1
    AND (
    	(MATCH(v.title, v.body) AGAINST ('keyword1 keyword2' IN BOOLEAN MODE))
    )
    AND (
    	(MATCH(v.title, v.body) AGAINST ('keyword3' IN BOOLEAN MODE))
    )
    ORDER BY node.nid DESC
    Et ça, ça prend 0,5 seconde :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.status = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    )
    AND (
    	(tn2.tid IN (3574))
    )
    ORDER BY node.nid DESC

  11. #11
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  12. #12
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    ? Non pas du tout, ce dont j'ai besoin, c'est que les deux requêtes fusionnées s'exécutent en environ 1 seconde au lieu de 18 ou alors qu'on me confirme que c'est impossible pour que j'essaie autrement, par ex. en combinant avec Apache Solr mais vu mon besoin particulier ça me semble difficile...

  13. #13
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Tu peux nous donner le résultat d'un EXPLAIN de la requête ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  14. #14
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Tu peux nous donner le résultat d'un EXPLAIN de la requête ?
    Voilà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    EXPLAIN SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.status = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('solar tata test' IN BOOLEAN MODE))
    )
    AND (
    	(tn2.tid IN (3574))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('test2' IN BOOLEAN MODE))
    )
    ORDER BY node.nid DESC
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
    1,PRIMARY,node,ref,"PRIMARY,vid,node_status_type,node_type",node_status_type,102,"const,const",12945,"Using where"
    1,PRIMARY,v,eq_ref,PRIMARY,PRIMARY,4,node.vid,1,
    1,PRIMARY,tn1,ref,"PRIMARY,nid,tid",nid,4,node.nid,12,"Using where"
    1,PRIMARY,tn2,ref,"PRIMARY,nid,tid",nid,4,tn1.nid,12,"Using where"
    2,"DEPENDENT SUBQUERY",h,eq_ref,"PRIMARY,nid",PRIMARY,8,"const,node.nid",1,"Using where; Using index"
    Encore merci

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Les résultats ne semblent pas catastrophiques mais ce qui coûte le plus est la première ligne avec 12945 lignes examinées. Elle indique que l'index utilisé est node_status_type et je vois dans la description de la table que tu as donnée plus haut que sa composition est : KEY `node_status_type` (`status`,`type`,`nid`),.
    Est-ce toi qui a placé cet index ou est-ce standard chez Drupal ?

    N'ayant pas Drupal installé sur ma machine, je ne peux pas vérifier.

    Si j'interprète correctement la chose, status doit être un booléen ou pas loin, type ne doit pas avoir beaucoup de valeurs différentes et la colonne qui a le plus de valeurs est probablement nid. Cet index est donc composé à l'envers car en principe on met la colonne la plus dispersée en premier.

    Tu peux essayer en désactivant cet index. Il devrait alors prendre l'index KEY `node_type` (`type`(4)), pour trouver les feed_item et il y a des chances que ça aille plus vite.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  16. #16
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    J'ai vérifié sur deux instances fraîches de Drupal 6 et ça semble standard.

    Oui, "status" est un genre de booléen qui indique si le node est publié ou pas. Dans toute ma table je n'ai trouvé que deux valeurs : 0 et 1.

    "type" correspond aux types de nodes. J'ai 15 valeurs différentes.

    "nid" correspond à l'id du node et est unique.

    J'ai supprimé l'index, ça m'a fait gagner environ une seconde, on passe donc à 17 secondes d'exécution Voilà le résultat du explain :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    id,	select_type,		table,	type,	possible_keys,			key,		key_len,	ref,			rows,	Extra
    1,	PRIMARY,		tn1,	ALL,	"PRIMARY,nid,tid",		NULL,		NULL,		NULL,			423244,	"Using temporary; Using filesort"
    1,	PRIMARY,		node,	eq_ref,	"PRIMARY,vid,node_type",	PRIMARY,	4,		ren21.tn1.nid,		1,	"Using where"
    1,	PRIMARY,		v,	eq_ref,	PRIMARY,			PRIMARY,	4,		ren21.node.vid,		1,	"Using where"
    1,	PRIMARY,		tn2,	ref,	"PRIMARY,nid,tid",		nid,		4,		ren21.tn1.nid,		12,	"Using where"
    2,	"DEPENDENT SUBQUERY",	h,	eq_ref,	"PRIMARY,nid",			PRIMARY,	8,		"const,ren21.node.nid",	1,	"Using where; Using index"

  17. #17
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Bizarre qu'il ne prenne pas l'index node_type comme je l'avais imaginé !

    Il semble scanner toute la table (423244 lignes examinées) sans utiliser d'index.

    Simplifie ta requête et fais un explain à chaque fois pour voir quelle clause produit l'examen d'autant de lignes.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  18. #18
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Cette query, sans la recherche fulltext, prend 0,3 sec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.STATUS = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    )
    AND (
    	(tn2.tid IN (3574))
    )
    ORDER BY node.nid DESC
    Voici le explain :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    id,	select_type,		table,	type,	possible_keys,			key,		key_len,	ref,			rows,	Extra
    1,	PRIMARY,		tn2,	ref,	"PRIMARY,nid,tid",		tid,		4,		const,			421,	"Using temporary; Using filesort"
    1,	PRIMARY,		tn1,	ref,	"PRIMARY,nid,tid",		nid,		4,		ren21.tn2.nid,		12,	"Using where"
    1,	PRIMARY,		node,	eq_ref,	"PRIMARY,vid,node_type",	PRIMARY,	4,		ren21.tn1.nid,		1,	"Using where"
    1,	PRIMARY,		v,	eq_ref,	PRIMARY,			PRIMARY,	4,		ren21.node.vid,		1,
    2,	"DEPENDENT SUBQUERY",	h,	eq_ref,	"PRIMARY,nid",			PRIMARY,	8,		"const,ren21.node.nid",	1,	"Using where; Using index"
    Lorsque j'ajoute une recherche fulltext, ça prend 1,7 sec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.STATUS = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('solar tata test' IN BOOLEAN MODE))
    )
    AND (
    	(tn2.tid IN (3574))
    )
    ORDER BY node.nid DESC
    Voici le explain :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    id,	select_type,		table,	type,	possible_keys,			key,		key_len,	ref,			rows,	Extra
    1,	PRIMARY,		tn2,	ref,	"PRIMARY,nid,tid",		tid,		4,		const,			421,	"Using temporary; Using filesort"
    1,	PRIMARY,		node,	eq_ref,	"PRIMARY,vid,node_type",	PRIMARY,	4,		ren21.tn2.nid,		1,	"Using where"
    1,	PRIMARY,		v,	eq_ref,	PRIMARY,			PRIMARY,	4,		ren21.node.vid,		1,
    1,	PRIMARY,		tn1,	ref,	"PRIMARY,nid,tid",		nid,		4,		ren21.tn2.nid,		12,	"Using where"
    2,	"DEPENDENT SUBQUERY",	h,	eq_ref,	"PRIMARY,nid",			PRIMARY,	8,		"const,ren21.node.nid",	1,	"Using where; Using index"
    Lorsque je met les deux recherches fulltext, ça prend 17 secondes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    SELECT
    	node.nid AS nid,
    	v.title AS node_title,
    	v.body AS node_revisions_body,
    	v.format AS node_revisions_format,
    	DATE_FORMAT(FROM_UNIXTIME(node.created), '%Y%m%d%H') AS node_created_hour
    FROM
    	node
    	INNER JOIN node_revisions v ON node.vid = v.vid
    	INNER JOIN term_node tn1 ON tn1.nid = node.nid
    	INNER JOIN term_node tn2 ON tn2.nid = node.nid
    WHERE
    NOT EXISTS
    (
      SELECT *
      FROM history h
      WHERE h.nid = node.nid
        AND h.uid = 1
    )
    AND node.type = 'feed_item'
    AND node.STATUS = 1
    AND (
    	(tn1.tid IN (15937, 12628))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('solar tata test' IN BOOLEAN MODE))
    )
    AND (
    	(tn2.tid IN (3574))
    	OR
    	(MATCH(v.title, v.body) AGAINST ('test2' IN BOOLEAN MODE))
    )
    ORDER BY node.nid DESC
    Voilà le explain :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    id,	select_type,		table,	type,	possible_keys,			key,		key_len,	ref,			rows,	Extra
    1,	PRIMARY,		tn1,	ALL,	"PRIMARY,nid,tid",		NULL,		NULL,		NULL,			423244,	"Using temporary; Using filesort"
    1,	PRIMARY,		node,	eq_ref,	"PRIMARY,vid,node_type",	PRIMARY,	4,		ren21.tn1.nid,		1,	"Using where"
    1,	PRIMARY,		v,	eq_ref,	PRIMARY,			PRIMARY,	4, 		ren21.node.vid,		1,	"Using where"
    1,	PRIMARY,		tn2,	ref,	"PRIMARY,nid,tid",		nid,		4,		ren21.tn1.nid,		12,	"Using where"
    2,	"DEPENDENT SUBQUERY",	h,	eq_ref,	"PRIMARY,nid",			PRIMARY,	8,		"const,ren21.node.nid",	1,	"Using where; Using index"

  19. #19
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Clairement, c'est le second MATCH qui pose problème, ce qui se voit aussi par le nombre de rows dans le résultat de l'EXPLAIN.

    As-tu essayé le second MATCH tout seul ?

    S'il est rapide, tu peux tenter une UNION de deux requêtes rapides.
    Dans ton message du 04/05/2012 16h34, tu disais que la requête avec seulement des MATCH prenait seulement 1 seconde et celle avec les autres conditions sans MATCH prenait seulement 0,5 seconde.
    Tu pourrait faire une union des deux pour voir si ça reste dans une plage de temps acceptable.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  20. #20
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Visiblement, le problème c'est d'avoir deux MATCH dans la même query. Avec un seul ça marche bien mais avec plus c'est super lent.

    Je ne vois pas comment contourner ce problème sans mettre de limitation au niveau fonctionnel pour l'utilisateur...

    Encore merci pour ton aide

Discussions similaires

  1. [SQL2K] Problème anormal de performance d'une requète
    Par G. Goossens dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 23/03/2006, 12h06
  2. Réponses: 2
    Dernier message: 02/03/2006, 11h57
  3. [SQL ] performances dans une requête
    Par claralavraie dans le forum Oracle
    Réponses: 12
    Dernier message: 05/01/2006, 17h54
  4. Aide pour écrire une requête complexe
    Par julienbdx dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 29/11/2005, 16h58
  5. Encore une requête complexe sur plusieurs tables
    Par DenPro dans le forum Langage SQL
    Réponses: 5
    Dernier message: 09/12/2003, 19h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo