Project

General

Profile

Anomalie #23635

Version 1.0+2-45 plante au reconf : la taille de l'index sur la table url est trop longue

Added by Renaud Dussol over 4 years ago. Updated about 4 years ago.

Status:
Fermé
Priority:
Normal
Assigned To:
Target version:
Start date:
04/16/2018
Due date:
% Done:

100%

Distribution:

Description

Sur run-parts: executing /usr/share/eole/postservice/30_dispatcher reconfigure

PHP Fatal error: Uncaught [42000] - SQLSTATE42000: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
trace: #0 /var/www/html/edispatcher/include/rb.php(651): RedBeanPHP\Driver\RPDO->runQuery('ALTER TABLE `u...', Array)
#1 /var/www/html/edispatcher/include/rb.php(2646): RedBeanPHP\Driver\RPDO->Execute('ALTER TABLE `u...', Array)
#2 /var/www/html/edispatcher/include/rb.php(8021): RedBeanPHP\Adapter\DBAdapter->exec('ALTER TABLE `u...', Array)
#3 /var/www/html/edispatcher/include/rb.php(8599): RedBeanPHP\Facade::query('exec', 'ALTER TABLE `u...', Array)
#4 /var/www/html/edispatcher/utils/createStructure.php(178): RedBeanPHP\Facade::exec('ALTER TABLE `u...')

Si on regarde /var/www/html/edispatcher/utils/createStructure.php :

178 \R::exec("ALTER TABLE `url` CHANGE `url` `url` VARCHAR;"); // fixes #22746

Apparemment en innoDB, la taille des index est limitée à 767 bytes...

Associated revisions

Revision 290e7a50 (diff)
Added by Christophe LEON over 4 years ago

fixes #24325 , ref #23635 , Mettre en place un flag pour le numéro de version de la base afin de gérer la migration de url => md5(url)

History

#1 Updated by Renaud Dussol over 4 years ago

Apparemment la taille max que l'on peut mettre est 191
Pourquoi ? Mystère pour l'instant...

#2 Updated by Nicolas Penot over 4 years ago

Pour ma part, j'avais remplacé la valeur 150 par 255 et ça fonctionne.

Voir ici : https://dev-eole.ac-dijon.fr/issues/22746#note-3

\R::exec("ALTER TABLE `url` CHANGE `url` `url` VARCHAR;");

#3 Updated by Nicolas Penot over 4 years ago

Il m'avait viré le 255 dans varchar ()...
J'avais écris :

\R::exec("ALTER TABLE  `url` CHANGE  `url`  `url` VARCHAR( 255 );");

#4 Updated by Renaud Dussol over 4 years ago

Réponse : en utf8mb4 (ce qui est le cas de notre table), chaque caractère occupe 4 bytes
En InnoDB la max size d'un préfixe est 767
Donc le max est 191 (192 x 4 = 768) si on reste en utf8mb4
Si on passe en utf8 simple on peut aller jusqu'à 255

Autres options : utiliser MyISAM (limite à 1000 bytes donc 250 cars en utf8mb4 et 333 en utf8)
Ou passer en latin1 mais bon...

#5 Updated by Renaud Dussol over 4 years ago

Le passage en MyISAM sera impossible vu qu'on a des clés étrangères et je pense qu'on utilise des transactions avec rb

Donc le max sera de 255 à moins de passer la colonne en latin1... Je peux tester

#6 Updated by Renaud Dussol over 4 years ago

Sur suggestion de C. Léon :

- créer un nouveau champ dans la table url nommé "md5url" CHAR (32) ascii_general_ci
- UPDATE URL set md5url = md5(url)
- virer l'index sur url
- mettre l'index sur md5url

TODO :
- modifier le createstructure
- côté appli :
- Lors de l'insert ajouter le md5url
- find sur le md5 au lieu de l'url

#7 Updated by Renaud Dussol over 4 years ago

  • Assigned To changed from Christophe LEON to Renaud Dussol

#8 Updated by Renaud Dussol over 4 years ago

Dans createStructure.php :

$eUrl->md5url     ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

.
.
.

//à la fin dans // Ajustement des autres champs
\R::exec("ALTER TABLE  `app` CHANGE  `uid`  `uid` VARCHAR( 50 );");
\R::exec("ALTER TABLE `url`  CHANGE `md5url` `md5url` CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL;");
\R::exec("UPDATE `url` SET `md5url`= md5(`url`);");

// A placer avant le passage en 2048
//Le try/catch pour éviter une erreur si l'index n'existe pas. apparemment le nom de l'index est tjs le même car généré en sha1
try {
       \R::exec("ALTER TABLE `url` DROP INDEX UQ_d199ec153ccff2bb155aa543f7c4957823daa439;");
   }catch( \Exception $e) {

}
try {
          \R::exec("ALTER TABLE `url` DROP INDEX url;");
 } catch( \Exception $e) {
}

\R::exec("ALTER TABLE  `url` CHANGE  `url`  `url` VARCHAR( 2048 );"); // fixes #22746 :
 \R::exec("ALTER TABLE `url` ADD INDEX(`url`);");

Je pense qu'il faut laisser un index sur url pour la recherche.
Je ne vois pas comment on peut utiliser une recherche (notamment en regexp, pour le motif) sur du md5. Seuls les 191 premiers caractères seront indexés mais c'est largement suffisant. Par contre je suis obligé d'ajouter un DROP INDEX avant pour pas qu'il n'en rajoute un à chaque reconf... Je n'ai pas trouvé comment le faire en redbean, j'ai essayé setMeta("buildcommand.indexes" , "url") mais ça ne marchait pas...

à la fin dans l'ajout des index
remplacer :
$u->setMeta("buildcommand.unique" , "url");
par :
$u->setMeta("buildcommand.unique" , "md5url");

QUESTION : du coup si on laisse un index sur url, a-t-on besoin de toucher au code php pour le find ? Même si ce n'est que sur les 191 premiers caractères ça me parait suffisant pour la plupart des cas ?

#9 Updated by Renaud Dussol over 4 years ago

Dans ApiController.php

575 // $eUrl=\R::findOne( 'url', 'url = ?', array($url));
576 $eUrl=\R::findOne( 'url', 'md5url = ?', array(md5($url)));

588 $eUrl->url = $url;
589 $eUrl->md5url = md5($url);
590 $eUrl->host = $host;

#10 Updated by Renaud Dussol over 4 years ago

Dans AppController.php

722 // if ($url = \R::findOne('url','url = ?',[$ressource->urlComplete])) {
723 if ($url = \R::findOne('url','md5url = ?',[md5($ressource->urlComplete)])) {

744 $url->url = $ressource->urlComplete;
745 $url->md5url = md5($ressource->urlComplete);
746 $url->libelle = $ressource->libelleRessource;

#11 Updated by Christophe LEON over 4 years ago

  • Status changed from Nouveau to En cours

Merci pour ces investigations
Elles sont sur une branche particulière pour que je les intègrent ?

#12 Updated by Renaud Dussol over 4 years ago

  • Status changed from En cours to Résolu
  • % Done changed from 0 to 100

#13 Updated by Arnaud FORNEROT over 4 years ago

  • Target version set to Envole 5.10

#14 Updated by Arnaud FORNEROT about 4 years ago

  • Status changed from Résolu to Fermé

Also available in: Atom PDF