Anomalie #23635
Version 1.0+2-45 plante au reconf : la taille de l'index sur la table url est trop longue
100%
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...
History
#1 Updated by Renaud Dussol almost 5 years ago
Apparemment la taille max que l'on peut mettre est 191
Pourquoi ? Mystère pour l'instant...
#2 Updated by Nicolas Penot almost 5 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 almost 5 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 almost 5 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 almost 5 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 almost 5 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 almost 5 years ago
- Assigned To changed from Christophe LEON to Renaud Dussol
#8 Updated by Renaud Dussol almost 5 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 almost 5 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 almost 5 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 almost 5 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 almost 5 years ago
- Status changed from En cours to Résolu
- % Done changed from 0 to 100
Appliqué par commit 818767a31fffc4fc9165d1b4eb29b1acd3bb740f.
#13 Updated by Arnaud FORNEROT almost 5 years ago
- Target version set to Envole 5.10
#14 Updated by Arnaud FORNEROT over 4 years ago
- Status changed from Résolu to Fermé