Plantage du processus mysql-nt a la suite d'une requête SQL.

Mammouth du PHP | 1511 Messages

27 août 2008, 16:41

SGBD: MySql Version 5.0.51b (Celle de Wamp)

Code : Tout sélectionner

SELECT f.id, f.name, f.description, f.status, f.catId, lp.id as lastPostId, lp.userId as lastPostUserId, lp.date as lastPostDate, m.name as lastPostUserName, (SELECT COUNT(DISTINCT pc.id) FROM forum_posts as pc, forum_topics as ft WHERE ft.forumId=f.id AND pc.topicId=ft.id) as repliesCount, (SELECT COUNT(DISTINCT tc.id) FROM forum_topics as tc WHERE tc.forumId=f.id) as topicsCount FROM forum_forums as f LEFT JOIN forum_posts as lp ON (SELECT flp.id FROM forum_posts as flp, forum_topics as flt WHERE (flt.forumId=f.id OR flt.forumId IN (SELECT sf.id FROM forum_forums as sf, forum_perms as sfp WHERE sfp.groupId='1' AND sfp.forumId=sf.id AND sfp.readForum='1' AND sf.parentId=f.id)) AND flp.topicId=flt.id ORDER BY flp.date DESC LIMIT 0, 1)=lp.id LEFT JOIN members as m ON lp.userId=m.id, forum_perms as fp WHERE fp.groupId='1' AND fp.forumId=f.id AND fp.readForum='1' AND f.parentId IS NULL ORDER BY f.position ASC

Code : Tout sélectionner

-- -- Structure de la table `forum_categories` -- CREATE TABLE `forum_categories` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL default 'Nouvelle Catégorie', `position` int(10) NOT NULL default '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ; -- -------------------------------------------------------- -- -- Structure de la table `forum_forums` -- CREATE TABLE `forum_forums` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL default 'Nouveau Forum', `description` text, `position` int(10) NOT NULL default '0', `catId` int(10) unsigned NOT NULL default '0', `parentId` int(10) unsigned default '0', `status` enum('0','1') NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=90 ; -- -------------------------------------------------------- -- -- Structure de la table `forum_posts` -- CREATE TABLE `forum_posts` ( `id` int(10) unsigned NOT NULL auto_increment, `userId` int(10) NOT NULL default '1', `authIp` varchar(15) collate latin1_general_ci default NULL, `content` text collate latin1_general_ci, `date` int(10) unsigned NOT NULL default '0', `topicId` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`id`), KEY `punbb_posts_topic_id_idx` (`topicId`), KEY `punbb_posts_multi_idx` (`userId`,`topicId`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=244996 ; -- -------------------------------------------------------- -- -- Structure de la table `forum_topics` -- CREATE TABLE `forum_topics` ( `id` int(10) unsigned NOT NULL auto_increment, `title` varchar(255) collate latin1_general_ci NOT NULL, `views` mediumint(8) unsigned NOT NULL default '0', `status` tinyint(1) NOT NULL default '0', `sticky` tinyint(1) NOT NULL default '0', `forumId` int(10) unsigned NOT NULL default '0', `isPoll` tinyint(1) NOT NULL, PRIMARY KEY (`id`), KEY `punbb_topics_forum_id_idx` (`forumId`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=24342 ;
Cette requête, après avoir importé des données du forum que je suis sensé migrer, fait planter le processus de Mysql.
J'ai droit a une jolie fenêtre pour me dire que mysql-nt a planté...

Certes, elle est un peu longue, mais avec les données de test, ca fonctionnait...

ViPHP
ViPHP | 4039 Messages

27 août 2008, 19:47

Non mais, on devrais te signaler à la cellule contre la maltraitance des DB's... :D

Code : Tout sélectionner

SELECT f.id, f.name, f.description, f.status, f.catId, lp.id as lastPostId, lp.userId as lastPostUserId, lp.date as lastPostDate, m.name as lastPostUserName, ( SELECT COUNT(DISTINCT pc.id) FROM forum_posts as pc, forum_topics as ft WHERE ft.forumId=f.id AND pc.topicId=ft.id) as repliesCount, ( SELECT COUNT(DISTINCT tc.id) FROM forum_topics as tc WHERE tc.forumId=f.id) as topicsCount FROM forum_forums as f LEFT JOIN forum_posts as lp ON ( SELECT flp.id FROM forum_posts as flp, forum_topics as flt WHERE (flt.forumId=f.id OR flt.forumId IN ( SELECT sf.id FROM forum_forums as sf, forum_perms as sfp WHERE sfp.groupId='1' AND sfp.forumId=sf.id AND sfp.readForum='1' AND sf.parentId=f.id)) AND flp.topicId=flt.id ORDER BY flp.date DESC LIMIT 0, 1)=lp.id LEFT JOIN members as m ON lp.userId=m.id, forum_perms as fp WHERE fp.groupId='1' AND fp.forumId=f.id AND fp.readForum='1' AND f.parentId IS NULL ORDER BY f.position ASC
Tu m'étonnes qu'il aie planté.. a sa place, rien qu'a en voir la gueule, je serais parti sur pluton le
temps d'y cultiver des fleurs.. On dit que les sous-requêtes, c'est mal, puisque ça plombe le tout.. tu
en fais 3, plus une sous-sous-requête.. a ta place, je prendrais un bon café, et j'essayerais de
penser tout ça dans un esprit 'SQL', à savoir, avec des tables. set-based thinking ça s'appelle dans
la langue de mr bean.

Ici, une source de mysql pour comment qu'il faut fezer pour transformer des sous-requêtes en joins:
http://dev.mysql.com/doc/refman/5.0/en/ ... eries.html

Et sinon, peut-être qu'un index a gauche ou a droite ferait un peu de bien à ta pauvre machine..
Modifié en dernier par Berzemus le 27 août 2008, 22:50, modifié 1 fois.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

ViPHP
ViPHP | 5924 Messages

27 août 2008, 20:42

Rha, c'est énorme :D

Mammouth du PHP | 1511 Messages

27 août 2008, 22:51

J'avoue que ce doit être la requete la plus lourde que j'ai du imaginer...
Le problème, c'est qu'a certains endroits, pour retrouver un résultat, je dois déjà passer par une autre table...
Ex: Pour retrouver le dernier post, je dois commencer par trouver les topics dudit forum puis le dernier post appartenant a un de ces topics...

Je pense que je vais deja commencer par trouver la requete pour faire ca...

EDIT: après réflexion et tests, il semblerait que ce soit surtout les clauses LIMIT qui fassent tout ralentir, faut dire aussi, avec une table de près de 15000 entrées...

EDIT 2:
Après tests, j'ai commencé a réecrier ladite requête.
J'en suis arrivé à:

Code : Tout sélectionner

SELECT f.id, f.name, f.description, f.status, f.catId, COUNT( DISTINCT ftc.id ) AS forumTopicsCount, COUNT( DISTINCT fpc.id ) AS forumPostsCount FROM forum_forums AS f JOIN forum_topics AS ftc ON ftc.forumId = f.id LEFT JOIN forum_posts AS fpc ON fpc.topicId = ftc.Id, forum_perms AS fp WHERE fp.groupId = '1' AND fp.forumId = f.id AND fp.readForum = '1' AND f.parentId IS NULL GROUP BY f.id ORDER BY f.position ASC
Après avoir mis en index les clefs utilisées dans les jointures, j'ai un temps de génération de la requête de près de 2s tout de même...
N'est-ce pas trop pour si peu ?
Donc maintenant, il me reste a voir pour cette partie là de la requête:

Code : Tout sélectionner

LEFT JOIN forum_posts as lp ON ( SELECT flp.id FROM forum_posts as flp, forum_topics as flt WHERE (flt.forumId=f.id OR flt.forumId IN ( SELECT sf.id FROM forum_forums as sf, forum_perms as sfp WHERE sfp.groupId='1' AND sfp.forumId=sf.id AND sfp.readForum='1' AND sf.parentId=f.id)) AND flp.topicId=flt.id ORDER BY flp.date DESC LIMIT 1)=lp.id LEFT JOIN members as m ON lp.userId=m.id, forum_perms as fp
Mais j'avoue que je séche... :?
La jointure devant être effectuée sur deux tables, via celle des topics et celle des posts, j'avoue secher un peu...