Affichage des articles dont le libellé est MySQL. Afficher tous les articles
Affichage des articles dont le libellé est MySQL. Afficher tous les articles

mardi 22 novembre 2016

Tables MyISAM - Recréer les index à partir des fichiers de structure (*.frm) et de données (*.MYD)

Que faire quand MySQL renvoie le code d'erreur #1017 ?

#1017 - Can't find file: 'ma_table' (errno: 2)
MySQL n'arrive pas à ouvrir l'un des fichiers de la structure d'une table MyISAM.

Un check de la table nous confirme le problème :

mysql> check table ma_table;
+-------------------+-------+----------+----------------------------------------+
| Table             | Op    | Msg_type | Msg_text                               |
+-------------------+-------+----------+----------------------------------------+
| ma_base.ma_table  | check | Error    | Can't find file: 'ma_table' (errno: 2) |
| ma_base.ma_table  | check | status   | Operation failed                       |
+-------------------+-------+----------+----------------------------------------+
2 rows in set (0.00 sec)


Rappel de la structure physique des tables MyISAM

Sur le plan physique, une table MyISAM est constituée de 3 fichiers :
  • La définition de la table : 'tbl_name.frm'
  • le fichier contenant les données 'tbl_name.MYD'
  • le fichier contenant les index 'tbl_name.MYI'
Dans notre cas, le fichier *.MYI n'existe plus ou n'existe pas (dans le cas d'une restauration d'un backup incomplet par exemple)

Réparer un table MyISAM corrompue



Comme le fichier *.MYI n'existe plus, on ne pourra pas utiliser l'utilitaire Myisamchk pour réparer cette table.

A la place, on utilisera la commande "REPAIR TABLE" de MySQL avec le mode "USE_FRM".

Ce mode est très utile dans le cas où, justement le fichier .MYI est manquant, ou erroné (entête corrompu par exemple).

Avec ce mode, MySQL va recréer intégralement le fichier d'index.MYI, en utilisant les informations du fichier .frm de la table et les données disponibles dans le fichier .MYD.


Syntaxe de la commande:
REPAIR TABLE tbl_name[,tbl_name...] [EXTENDED] [USE_FRM]

Test de réparation sur une table corrompue


mysql> repair table ma_table USE_FRM;
+-------------------+--------+----------+-------------------------------------+
| Table             | Op     | Msg_type | Msg_text                            |
+-------------------+--------+----------+-------------------------------------+
| ma_base.ma_table  | repair | warning  | Number of rows changed from 0 to 14 |
| ma_base.ma_table  | repair | status   | OK                                  |
+-------------------+--------+----------+-------------------------------------+
2 rows in set (0.01 sec)


La réparation est un succès !

Un check de la table nous le confirme :


mysql> check table ma_table;
+-------------------+-------+----------+----------+
| Table             | Op    | Msg_type | Msg_text |
+-------------------+-------+----------+----------+
| ma_base.ma_table  | check | status   | OK       |
+-------------------+-------+----------+----------+
1 row in set (0.00 sec)


Cette démarche est très utile. mais lorsque le problème se pose pour de nombreuses tables, il faut industrialiser le processus.

Réparer un ensemble de table MyISAM corrompues

On va écrire un petit script basé sur le procédé que l'on vient de décrire.

Ce scritp pourra être lancé directement depuis l'arborescence de MySQL.
A noter que le Serveur MySQL doit être en fonctionnement.

for i in `ls *.frm`
do
    # On récupère le nom de la table à partir du nom du fichier *.frm
    l=${#i}-4;
    n=${i:0:l};
  
    echo $n;

    # On lance la réparation et le check
    mysql -u root -pxxxxx -D YYYY -B -e "-- REPAIR TABLE $n USE_FRM; CHECK TABLE $n";
    # avec :
    # -B : Mode batch - Pas d'historique
    # -e : Execute la requete et quitte
done



La ligne de commande renvoie les résultats de l'opération :
ma_base.autre_table     repair  warning Number of rows changed from 0 to 73364
ma_base.
autre_table     repair  status  OK
ma_base.
autre_table     check  status  OK



Well done !



Il ne reste plus qu'a vérifier que tout s'est bien passé et finaliser les dernier détails comme régler la valeur de l'auto-incrément, perdu dans la bataille...

Puis on lance un optimize sur toute les tables
Reprendre le code et remplace la ligne de réparation par :

mysql -u root -pxxxxx -D YYYY -B -e "-- OPTIMIZE TABLE $n ;";

+----------------------+-------+----------+----------+
| ma_base.autre_table  | check | status   | OK       |
+----------------------+-------+----------+----------+


Pour finir, on recharge toutes les tables à l'aide de Flush tables;
On peut également finir l'opération par un restart du serveur MySQL!


Have Fun !

Liens :
- http://dev.mysql.com/doc/refman/5.0/fr/repair.html

- http://dev.mysql.com/doc/refman/5.0/fr/repair-table.html



lundi 20 juin 2016

Désactiver MySQL / PostGreSQL sur Debian

Il peut arriver d'avoir besoin de désactiver un serveur MySQL ou  PostGreSQL


pour cela, il suffit d'agir sur le démon qui contrôle le service

MySQL


Arrêter le serveur MySQL avec la commande classique :
root@----:~# /etc/init.d/mysql stop
[ ok ] Stopping MySQL database server: mysqld.


(ré)Activer ou désactiver un démon (avec sa configuration par défaut et ses niveaux d'exécution (avec sa configuration par défaut et ses niveaux d'exécution) :

root@----:~#  update-rc.d mysql disable [| enable]
update-rc.d: using dependency based boot sequencing
insserv: warning: current start runlevel(s) (empty) of script `mysql' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (0 1 2 3 4 5 6) of script `mysql' overrides LSB defaults (0 1 6).


That's all !!

PostGreSQL

Arret du serveur PostGreSQL:

root@----:~# /etc/init.d/postgresql stop 

Désactivation du démon PostGreSQL :

root@----:~#  update-rc.d postgresql disable

Plus d'info sur le wiki Debian - Daemon

mardi 15 avril 2014

Optimiser les temps de réponse de MySQL - le DNS

Logo MySQL
Accélérer le temps de réponse de MySQL en désactivant la résolution DNS





Pour traiter des quantités importantes de données (quelques millions de lignes), j'utilise Talend Open Studio for Data Integration.
Toutes mes bases de données MySQL sont hébergées sur une VM (VirtualBox / Debian) en local.

Or, j'ai un petit problème de résolution de nom lié aux règles de sécurité drastiques, ce qui fait que MySQL patauge un peu quand je l’interroge depuis ma machine, que ce soit avec Talend ou autre chose (MySQL WorkBench...) car il veut absolument résoudre mon IP :(

Donc pour contourner ce petit 'problème', il suffit  de désactiver la résolution DNS dans MySQL

Pour cela, ajoutez un ligne dans le fichier de configuration de MySQL (my.cnf) avec l'option suivante :

skip-name-resolve

et redémarrez le serveur MySQL

Et là ! ca marche mieux !

La doc : http://dev.mysql.com/doc/refman/5.1/fr/dns.html

mercredi 6 juin 2012

Piwik error after update from 1.7.1 to 1.8.2

Erreur après la mise à jour de piwik depuis la version 1.7.1 vers 1.8.2


Une petite erreur rencontrée lors de la mise à jour automatique de piwik après la mise à jour de la base de données :

SQLSTATE[42000]: Syntax error or access violation: 1044 Access denied for user 'piwik'@'localhost' to database 'piwik'
 Go to Piwik
 Login
 Backtrace:

 #0 /var/www/piwik-1.5.1/core/PluginsFunctions/Sql.php(51): Zend_Db_Adapter_Pdo_Abstract->exec('LOCK TABLES pwk...')
 #1 /var/www/piwik-1.5.1/core/PluginsFunctions/Sql.php(205): Piwik_Sql::exec('LOCK TABLES pwk...')
 #2 /var/www/piwik-1.5.1/core/PluginsFunctions/Sql.php(359): Piwik_Sql::lockTables('pwk_archive_num...', 'pwk_archive_num...')
 #3 /var/www/piwik-1.5.1/core/ArchiveProcessing.php(688): Piwik_LockTables('pwk_archive_num...', 'pwk_archive_num...')
 #4 /var/www/piwik-1.5.1/core/ArchiveProcessing.php(533): Piwik_ArchiveProcessing->loadNextIdarchive()
 #5 /var/www/piwik-1.5.1/core/ArchiveProcessing.php(472): Piwik_ArchiveProcessing->initCompute()
 #6 /var/www/piwik-1.5.1/core/Archive/Single.php(226): Piwik_ArchiveProcessing->launchArchiving()
 #7 /var/www/piwik-1.5.1/core/Archive/Array/IndexedBySite.php(192): Piwik_Archive_Single->prepareArchive()
 #8 /var/www/piwik-1.5.1/core/Archive/Array/IndexedBySite.php(131): Piwik_Archive_Array_IndexedBySite->getArchiveIdsAfterLaunching(Array)
 #9 /var/www/piwik-1.5.1/core/Archive/Array/IndexedBySite.php(108): Piwik_Archive_Array_IndexedBySite->loadValuesFromDB(Array)
 #10 /var/www/piwik-1.5.1/core/Archive/Array/IndexedBySite.php(73): Piwik_Archive_Array_IndexedBySite->getValues(Array)
 #11 /var/www/piwik-1.5.1/plugins/MultiSites/API.php(120): Piwik_Archive_Array_IndexedBySite->getDataTableFromNumeric(Array)
 #12 /var/www/piwik-1.5.1/plugins/MultiSites/Controller.php(65): Piwik_MultiSites_API->getAll('day', '2012-06-06', false)
 #13 /var/www/piwik-1.5.1/plugins/MultiSites/Controller.php(37): Piwik_MultiSites_Controller->getSitesInfo(Object(Piwik_View))
 #14 [internal function]: Piwik_MultiSites_Controller->index()
 #15 /var/www/piwik-1.5.1/core/FrontController.php(138): call_user_func_array(Array, Array)
 #16 /var/www/piwik-1.5.1/index.php(53): Piwik_FrontController->dispatch()



La ligne #0 du log indique que l'utilisateur MySQL 'piwik' n'a pas le droit de poser de verrous (privilège '__LOCK TABLES__' ) sur les tables de la base 'piwik'.

Ce qui est normal puisque je ne lui ai pas donné ce droit ;)

Donc, en plus de privilèges existants, à savoir :
* SELECT
* INSERT
* UPDATE
* DELETE
* CREATE
* DROP
* INDEX
* ALTER
* CREATE VIEW
* SHOW VIEW

Il faut ajouter le privilège d'administration  LOCK TABLES  :

REVOKE ALL PRIVILEGES ON `piwik`.* FROM 'piwik'@'localhost';
 GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES, CREATE VIEW, SHOW VIEW
ON `piwik`.* TO 'piwik'@'localhost';

 
Et on oublie pas de recharger les privilèges, ca ne coute rien !
FLUSH PRIVILEGES ;
 
Et c'est reparti !

En résumé, il s'agit plus d'un problème de droits MySQL (un peu trop stricts) que d'un bug de Piwik. D’ailleurs, la FAQ de Piwik est claire sur ce point :

The Mysql USER should have the permission to SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, LOCK.

Have fun !

mercredi 16 mars 2011

MySQL - Créer une table de sauvegarde en SQL

Astuce MySQL pour créer rapidement, en SQL, une table de sauvegarde





SET @tableName = concat ('ma_table_bak_',DATE_FORMAT(now(), '%Y_%m_%d_%H_%i'));
SET @sql := CONCAT('CREATE TABLE ', @tableName,' LIKE `ma_table`;');
PREPARE mySt FROM @sql; 
EXECUTE mySt; SET @sql2 := CONCAT('INSERT INTO ', @tableName,' SELECT * FROM `ma_table`'); 
PREPARE mySt2 FROM @sql2;
EXECUTE mySt2;

mardi 20 avril 2010

Débordé



Pas trop le temps de bloguer en ce moment :
  • Formation Techniques de Virtualisation chez Linagora (fin mars)
  • Formation MySQL DBA chez Anaska (début avril - Sympa les grèves à la SNCF)
  • Tests de solutions Haute Disponibilité Linux : Kvm/QEmu,Xen - Ovirt - HeartBeat - DRBD - iScsi
Les autres formations arrivent :
  • Formation LPIC 102 + Certification LPIC 101 +102 chez Linagora (début juin)
  • Formation MySQL HA chez Anaska (en mai)
Fiouuuu !

J'en profite pour saluer mes co-formés et les formateurs !

jeudi 18 mars 2010

MySQL - Modifier le prompt du client

Logo MySQL, fév. 2010



Encore un billet de qualité sur dbnewz.com sur la personnalisation du prompt de Mysql.




Pour ma part, j'ajoute à mon /etc/my.cnf les directives suivantes :

 [mysql]                     // Section du client mysql
 prompt=(\\u@\\h) [\\d]>\\_  // Affiche un prompt indiquant l'utilisateur, la machine et la base courante
Plus d'info sur la page d'aide de la commande mysql
Happy MySQL !

mercredi 3 mars 2010

MySQL - Activer le cache de requêtes


Depuis la version 4.0.1, MySQL server bénéficie d'un cache de requêtes.

Si une requête identique est appelée par la suite, le serveur retournera le résultat à partir du cache plutôt que d'analyser puis exécuter la requête à nouveau.


Le cache de requêtes est extrêmement utile dans un environnement où les tables ne changent pas souvent, et que vous avez de nombreuses requêtes identiques.
C'est la situation classique des serveurs Web, qui génèrent beaucoup de pages dynamiques à partir du même contenu.

Utiliser le cache de requête est très utile si vous avez beaucoup de lecture et peu de modifications d'enregistrements. Ex: présentation de contenu dynamique sur un site web.

A Noter : Le cache est sensible à la casse : pour lui la requête Select * FROM ... est différente de ''SELECT * FROM ...'".
Les deux résultats, identiques, seront stockés dans le cache, alors soyez rigoureux dans votre code.

Par défaut, le cache de requêtes est paramétré à minima ...

mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
1 row in set (0.00 sec)
 
...mais n'est pas actif :

mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+-------+
| Variable_name           | Value | 
+-------------------------+-------+
| Qcache_free_blocks      | 0     | 
| Qcache_free_memory      | 0     | 
| Qcache_hits             | 0     | 
| Qcache_inserts          | 0     | 
| Qcache_lowmem_prunes    | 0     | 
| Qcache_not_cached       | 0     | 
| Qcache_queries_in_cache | 0     | 
| Qcache_total_blocks     | 0     | 
+-------------------------+-------+
8 rows in set (0.00 sec)

Pour l'activer, il faut passer quelques paramètres au serveur MySQL.

En ligne
C'est le mieux pour un serveur en production qui ne peut pas être redémarrer à la demande. De plus vous pouvez pouvez ajuster les valeur en fonctions de vos besoins.

mysql> SET GLOBAL query_cache_type = 1;
Query OK, 0 rows affected (0.00 sec) 

mysql> SET GLOBAL query_cache_limit=2097152;
Query OK, 0 rows affected (0.00 sec) 
 
mysql> SET GLOBAL query_cache_size=32M;
Query OK, 0 rows affected (0.00 sec)
 
Ces valeurs sont données à titre d'exemple. Je vous laisse le soin de les adapter à votre contexte.

On attend quelques minutes et on jette un oeil :

mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 177      | // Nombre de blocs de mémoire libre dans la cache de requêtes. 
| Qcache_free_memory      | 32759616 | // Quantité de mémoire libre dans la cache de requêtes. 
| Qcache_hits             | 13238    | // Nombre de succès dans la cache. 
| Qcache_inserts          | 1599     | // Nombre de requêtes ajoutées à la cache. 
| Qcache_lowmem_prunes    | 0        | // Nombre de requêtes qui ont été retirées de la cache pour libérer de la mémoire afin de mettre en cache de nouvelles requêtes. Peut être utilisé afin de peaufiner la taille de la cache. La stratégie utilisée pour déterminer quelles requêtes seront retirées est LRU (least recently used).
| Qcache_not_cached       | 26       | // Nombre de requêtes non en cache (impossible à placer en cache, ou non cachée en raison du paramètre query_cache_type).
| Qcache_queries_in_cache | 548      | // Nombre de requêtes enregistrées dans la cache. 
| Qcache_total_blocks     | 1316     | // Nombre total de blocs dans la cache de requêtes. 
+-------------------------+----------+
8 rows in set (0.00 sec)
 
N'oubliez pas de sauvegarder vos réglages dans le fichier de conf de MySQL.

Au lancement du serveur
  • Editer le fichier de configuration /etc/my.cnf et ajouter les lignes suivantes:
#Query Cache
query_cache_type=1    // Cache all cacheable query results except for those that begin with SELECT SQL_NO_CACHE.
query_cache_limit=4M  // Don't cache results that are larger than this number of bytes. The default value is 1MB.
query_cache_size=8M   // The amount of memory allocated for caching query results. The default value is 0, which disables the query cache. The allowable values are multiples of 1024; other values are rounded down to the nearest multiple.
  • Redémarrer le serveur MySQL pour que les paramètres soient pris en compte.
Vous pouvez aussi ajouter des paramètres au lancement du daemon, mais ce n'est pas forcément une bonne idée car les scripts de démarrages sont écrasés à chaque mise à jour des paquets.

Reste à patienter quelques jours pour apprécier le résultat. Tunnez les paramètres si besoin !

Have Fun !

Pour aller plus loin :