web-dev-qa-db-fra.com

Un script mal écrit cause une consommation élevée de ressources

Récemment, l’administrateur d’un serveur a envoyé un rapport sur un site Joomla qui entraîne une consommation excessive de ressources. Le rapport disait:

CAUSE DE CONSOMMATION HAUTE RESSOURCE:

Nous avons mené une enquête détaillée et il s'est avéré que Joomla exécutait des requêtes lentes vers sa base de données, ce qui finissait par piéger le serveur. Le serveur tente d'exécuter vos requêtes lentes tout en plaçant d'autres processus dans la file d'attente jusqu'à ce que de la mémoire soit libérée. Pendant qu’ils attendent, ils s’empilent et posent d’autres problèmes. Les requêtes de base de données lentes peuvent avoir de nombreuses raisons, mais les 3 suivantes sont les plus courantes:

  1. Grande base de données
  2. Scripts pas bien écrits
  3. Grand nombre de liens internes qui interrogent directement la base de données.

Voici quelques-unes des requêtes de base de données qui sont lentes et consomment beaucoup de ressources du serveur:

  1. Exécutée il y a 1h 8m 56s pour 87.512348 sec sur Base de données -> sporthis_tory Date: 2015-08-24 22:24:22 Heure de la requête: 87.512348 Rangée_réglée: 5593: Rangée_sent 247 Heure du verrou: 0.000197 SELECT a.id, CASE WHEN CHAR_LENGTH a.alias ) THEN CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) THEN CONCAT_WS (':', cc.id, cc.alias) ALSE cc. id END en tant que cul de chat FROM g06j5_content en tant que joint gauche g06j5_categories AS cc ON cc.id = a.catid WHERE a.catid = 105 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:22 : 36 ') ORDER BY a.created DESC; --------------------------------------- ----------------------------------------> --------- --------------
  2. Exécuté 57m Il y a pour 67.095903 sec sur la base de données -> sporthis_tory Date: 2015-08-24 22:36:11 Heure de la requête: 67.095903 Rangée_examinée: 5593: Rangée_sent 247 Heure du verrou: 0.000252 SELECT a.id, CASE WHEN CHAR_LENGTH (a.alias) THEN CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) PUIS CONCAT_WS (':', cc.id, cc.alias) ELSE cc.id FIN comme gifle FROM g06j5_content COMME GAUCHE JOIN g06j5_categories AS cc ON cc.id = a.catid WHERE a.catid = 105 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:35: 01 ') ORDER BY a.created DESC; -------------------------------------------- ---------------------------------------> ---------- -------------
  3. Exécutée il y a 1h 8m 56s pour le 52.137859 sec sur la base de données -> sporthis_tory Date: 2015-08-24 22:24:22 Heure de la requête: 52.137859 Rangée_réglée: 5593: Rangée_sent 247 Heure du verrou: 0.000169 SELECT a.id, CASE WHEN CHAR_LENGTH a.alias ) THEN CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) THEN CONCAT_WS (':', cc.id, cc.alias) ALSE cc. id END en tant que cul de chat FROM g06j5_content en tant que joint gauche g06j5_categories AS cc ON cc.id = a.catid WHERE a.catid = 105 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:22 : 52 ') ORDER BY a.created DESC; --------------------------------------- ----------------------------------------> --------- --------------
  4. Date d'exécution: il y a 1h 3m 29s pour 45.861259 sec sur la base de données -> sporthis_tory Date: 2015-08-24 22:29:49 Heure de la requête: 45.861259 Rangée_examinée: 5593: Rangée_sent 247 Heure du verrou: 0.000650 SELECT a.id, CASE WHEN CHAR_LENGTH (a.alias ) THEN CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) THEN CONCAT_WS (':', cc.id, cc.alias) ALSE cc. id END en tant que cul de chat FROM g06j5_content en tant que joint gauche g06j5_categories AS cc ON cc.id = a.catid WHERE a.catid = 105 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:28 : 40 ') ORDER BY a.created DESC; --------------------------------------- ----------------------------------------> --------- --------------
  5. Date d'exécution: 1h 20m 37s pour 40.682781 sec sur la base de données -> sporthis_tory Date: 2015-08-24 22:12:41 Interrogation de la requête: 40.682781 Rangée_examinée: 1320: Rangée_sent 440 Heure du verrou: 0.000176 SELECT a.id, CASE WHEN CHAR_LENGTH (a.alias ) THEN CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) THEN CONCAT_WS (':', cc.id, cc.alias) ALSE cc. id END en tant que cul de chat FROM g06j5_content EN TANT QUE LEFT JOIN g06j5_categories AS cc ON cc.id = a.catid WHERE a.catid = 111 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:11 : 50 ') ORDONNER PAR UN DESC.

sporthis_tory 175.1 MB

D'après les requêtes ci-dessus, nous pouvons conclure que votre problème est dû à un script mal écrit.

J'aimerais savoir comment commencer à déboguer quelque chose comme ceci (trouver les scripts qui exécutent la requête, optimiser la base de données), ou est-ce simplement le site qui se développe et que nous devons acheter un plan plus grand?

Mise à jour:

Merci pour les informations utiles. Je souhaite ajouter que ce site est hors service en raison de la consommation de ressources. Je ne peux donc pas me connecter pour accéder à joomla admin panel tant que je n'ai pas résolu le problème. J'ai couru expliquer étendu avec la requête et obtenu ce résultat>>

id: 1
select_type: SIMPLE
tableau: a
type: index_merge
possible_keys: idx_access, idx_state, idx_catid
clé: idx_catid, idx_state, idx_access
Key_len: 4,1,4
ref: NULL
rangées: 1275
filtré: 75.06
Extra: Utilisation de intersect (idx_catid, idx_state, idx_access); Utiliser où; Utiliser le porte-fichiers

id: 1
select_type: SIMPLE
tableau: cc
type: const
possible_keys: PRIMARY
Touche : PRIMAIRE
Key_len: 4
ref: const
rangées: 1
filtré: 100.00
Supplémentaire:

Je n'ai aucune expérience en indexation de bases de données et je souhaite obtenir ce droit. Je dois créer un nouvel index avec les trois colonnes (idx_catid, idx_state, idx_access) ou sont-elles déjà indexées? En outre, je pense que cette requête provient d’un module joomla. Existe-t-il un moyen de découvrir quel module exécute cette requête étrange? Notez que je ne suis pas le créateur du site, on vient de me demander de résoudre ce problème.

2
Agapios Iwsifidis

Bien que vous puissiez prendre de nombreuses mesures pour résoudre ce problème, ma recommandation principale devrait être très rapide, espérons-le.

Tout d’abord, comment résoudre ces problèmes. Puisqu'ils vous donnent les requêtes lentes, vous devriez commencer par voir pourquoi elles sont lentes! La base de données vous le dira dans une certaine mesure, alors connectez-vous à votre base de données (en utilisant la ligne de commande ou quelque chose comme PhpMyAdmin). Exécutez l'une des requêtes lentes avec le mot EXPLAIN au début:

EXPLAIN SELECT a.id, CASE QUAND CHAR_LENGTH (a.alias) ALORS CONCAT_WS (':', a.id, a.alias) SINON a.id END comme slug, CASE WHEN CHAR_LENGTH (cc.alias) THEN CONCAT_WS (': ', cc.id, cc.alias) SINON cc.id END en tant que chat félin DE g06j5_content en tant que membre de gauche du groupe g06j5_categories en tant que cc ON cc.id = a.catid WHERE a.catid = 105 AND a.state = 1 AND a.access = 1 AND (a.state = 1 OR a.state = -1) AND (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:22:36 ') ORDER BY a.created DESC;

Cela devrait vous donner un tableau de données vous indiquant comment votre base de données va obtenir cette information. Choses que je m'attendrais à voir dans ceci (sans avoir réellement exécuté l'expliquer ...):

  • La jointure est sur l'id pour #__categories, donc cela devrait charger la table supplémentaire avec une clé
  • Il devrait également vous indiquer quelle clé (le cas échéant) il utilise pour charger les enregistrements de la table #__content. Joomla par défaut est livré avec un index sur catid, state et access, qui sont tous dans votre clause WHERE et peuvent donc être utilisés

Ma recommandation pour l'optimisation est généralement de déterminer quel index il essaie d'utiliser, puis d'ajouter un meilleur index à la table pour prendre en charge ce type de requête. (Et rappelez-vous que le compromis avec les index est toujours un temps de lecture plus rapide pour un temps d'écriture plus lent, donc si vous ajoutez beaucoup d'index, vous devriez pouvoir sélectionner des enregistrements plus rapidement, mais ajouter de nouveaux enregistrements plus lentement.)

Lorsque vous examinez tout ce que vous sélectionnez, vous souhaitez définir un catid, un état et un accès spécifiques. L'ajout d'un index utilisant ces trois colonnes en même temps devrait permettre à la base de données de sélectionner les lignes appropriées encore plus rapidement. Il y aura toujours des processus de base de données car il devra les trier par created pour les commander.

Pour prendre votre décision, je vous recommande de copier la base de données de votre site Web localement, d'ajouter différents index à la table g06j5_content et de continuer à exécuter cette requête EXPLAIN jusqu'à ce que la requête soit exécutée principalement à partir d'index.


Une note supplémentaire, vous pouvez voir dans vos requêtes que vous faites une vérification à la fois pour a.state = 1 Et (a.state = 1 OR a.state = -1). Ceci est évidemment une vérification inutile, puisque l'état ne peut pas être égal à 1 et -1 pour le même enregistrement, ce qui signifie qu'avoir (a.state = 1 OR a.state = -1) Dans ce document est inutile.

Je ne recommande pas d'essayer de localiser quoi que ce soit de ce genre et de le supprimer, car la base de données dispose d'un optimiseur de requête qui supprimera le deuxième contrôle (car il n'ajoute aucune valeur).

Si vous souhaitez réellement modifier la requête, je voudrais comprendre pourquoi vous sélectionnez deux temps de publication exacts: (publish_up = '0000-00-00 00:00:00' OR publish_up = '2015-08-25 03:11:50').

Il n'y a pas d'index sur les temps de publication, ce qui signifie généralement que la base de données doit rechercher chaque enregistrement pour déterminer si cela est vrai ou non. Je ne suis pas sûr de la logique de soulignement dans la sélection en fonction d'une heure de publication spécifique, car cela sera rarement vrai.

2
David Fritsch

Vous pouvez activer le mode débogage dans les paramètres Joomla. Cela imprimera une jolie liste de toutes les requêtes à la fin de chaque page, y compris de nombreuses informations de débogage. Cette liste vous indique également combien de temps une requête a pris et quels index elle utilise.

Il semble également que vous ayez 5593 articles dans votre base de données, ce qui pourrait expliquer pourquoi cela a pris si longtemps, peut-être que les index par défaut n’aident en rien un aussi grand nombre d’articles.

2
Harald Leithner