Comment supprimer des tables vides

11

Est-il possible de supprimer toutes les tables vides de mon énorme base de données (mysql)?

Je recherche une commande sql pour supprimer automatiquement toutes ces tables vides.

Actuellement, j'ai 305 tables dans mon jeu de données, et environ 30% d'entre elles sont d'anciennes tables vides, qui ne seront pas utilisées dans ma nouvelle application.

Juste pour clarifier; Toutes les tables sont de type = MyISAM

qualbeen
la source
1
Est-ce que toutes les tables sont MyISAM, InnoDB ou un mélange des deux ???
RolandoMySQLDBA
Ils sont tous MyISAM
qualbeen

Réponses:

11

L'idée serait probablement de chercher les tables vides en utilisant INFORMATION_SCHEMA.TABLES

SELECT * 
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_ROWS =  '0'
AND TABLE_SCHEMA = 'my_database_only'

Ensuite, vous pourrez peut-être produire une requête SQL avec

SELECT CONCAT('DROP TABLE ', GROUP_CONCAT(table_name), ';') AS query
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_ROWS = '0'
AND TABLE_SCHEMA = 'my_database_only';

Rapide et un peu sale, mais devrait en fait fonctionner.

Tom Desp
la source
3
... et puis vous avez un serveur de base de données cassé parce que vous avez "probablement" supprimé certaines des tables système mysql ... outre le fait que votre CONCAT produit une liste de tables sans référence de schéma.
Cristian Porta
1
Vous avez également le "droit" d'ajouter intelligemment des restrictions de base de données à vos tables, je pensais que c'était évident.
Tom Desp
3
la réponse ne doit rien tenir pour acquis car la réponse est potentiellement dangereuse pour l'utilisateur ... c'est tout
Cristian Porta
2
+1 pour configurer une seule commande DROP TABLE.
RolandoMySQLDBA
1
@CP: Ok je comprends, ma terrible erreur, c'est pourquoi j'ai édité la réponse. Soit dit en passant, je suis un peu surpris qu'une requête SQL puisse réellement supprimer une table interne du système MySQL. De mon point de vue, c'est totalement cassé.
Tom Desp
7

Étant donné que toutes les tables sont MyISAM, cela rend ma réponse plus facile à exprimer.

Tout d'abord, vous devez interroger INFORMATION_SCHEMA pour les tables qui n'ont aucune ligne:

SELECT table_schema,table_name FROM information_schema.tables
WHERE table_rows = 0 AND table_schema NOT IN
('information_schema','mysql','performance_schema');

Ensuite, formulez la requête pour supprimer les tables vides:

SELECT CONCAT('DROP TABLE ',table_schema,'.',table_name,';') DropTableCommand
FROM information_schema.tables
WHERE table_rows = 0 AND table_schema NOT IN
('information_schema','mysql','performance_schema');

Maintenant, sauvegardez les commandes dans un fichier texte SQL externe.

SQL="SELECT CONCAT('DROP TABLE ',table_schema,'.',table_name,';') DropTableCommand"
SQL="${SQL} FROM information_schema.tables WHERE table_rows = 0 AND table_schema"
SQL="${SQL} NOT IN ('information_schema','mysql','performance_schema')"
mysql -uroot -p -ANe"${SQL}" > DropTables.sql

Regardez le contenu avec l'un des éléments suivants

  • less DropTables.sql
  • cat DropTables.sql

Si vous êtes satisfait de son contenu, exécutez le script:

mysql -uroot -p < DropTables.sql

ou connectez-vous à mysql et exécutez-le comme ceci:

mysql> source DropTables.sql

Essaie !!!

CAVEAT : cette technique ne fonctionne qu'avec la table MyISAM car le nombre de lignes d'une table MyISAM est physiquement stocké dans .MYDles tables. La table de métadonnées INFORMATION_SCHEMA.TABLES est toujours en train de lire et de mettre à jour. N'ESSAYEZ PAS CELA AVEC INNODB !!!

MISE À JOUR 2014-02-05 11:46 EST

Il y a une raison pour laquelle j'ai exclu ('information_schema','mysql','performance_schema')

Le mysqlschéma contient des tables vides. Certains MyISAM, certains InnoDB, certains CSV.

Par exemple, voici mes tables dans le schéma mysql pour MySQL 5.6.15 sur mon bureau

mysql> select table_name,engine,table_rows
    -> from information_schema.tables
    -> where table_schema='mysql';
+---------------------------+--------+------------+
| table_name                | engine | table_rows |
+---------------------------+--------+------------+
| columns_priv              | MyISAM |          0 |
| db                        | MyISAM |          2 |
| event                     | MyISAM |          0 |
| func                      | MyISAM |          0 |
| general_log               | CSV    |          2 |
| help_category             | MyISAM |         40 |
| help_keyword              | MyISAM |        485 |
| help_relation             | MyISAM |       1090 |
| help_topic                | MyISAM |        534 |
| innodb_index_stats        | InnoDB |          0 |
| innodb_table_stats        | InnoDB |          0 |
| ndb_binlog_index          | MyISAM |          0 |
| plugin                    | MyISAM |          0 |
| proc                      | MyISAM |          0 |
| procs_priv                | MyISAM |          0 |
| proxies_priv              | MyISAM |          1 |
| servers                   | MyISAM |          0 |
| slave_master_info         | InnoDB |          0 |
| slave_relay_log_info      | InnoDB |          0 |
| slave_worker_info         | InnoDB |          0 |
| slow_log                  | CSV    |          2 |
| tables_priv               | MyISAM |          0 |
| time_zone                 | MyISAM |          0 |
| time_zone_leap_second     | MyISAM |          0 |
| time_zone_name            | MyISAM |          0 |
| time_zone_transition      | MyISAM |          0 |
| time_zone_transition_type | MyISAM |          0 |
| user                      | MyISAM |          6 |
+---------------------------+--------+------------+
28 rows in set (0.01 sec)

mysql>

Si certains de ces tableaux devaient disparaître (comme columns_priv, proc_priv, tables_priv, etc.), le mécanisme de subvention peut ne pas fonctionner correctement ou peut causer mysqld de ne pas démarrer. Vous ne voulez pas non plus casser le fichier mysql.proc car il s'agit de la base physique des procédures stockées. D'autres mécanismes peuvent ne pas fonctionner si vous souhaitez les utiliser, comme la réplication CrashSafe en utilisant les tables InnoDB à l'intérieur du schéma mysql, ou si vous souhaitez insérer des informations de fuseau horaire.

MISE À JOUR 2014-02-05 12:36 EST

Je tiens à féliciter Tom Desp pour sa réponse pour une raison spécifique: sa syntaxe pourrait faire le drop sans utiliser de script externe . En utilisant son idée, permettez-moi de capturer la commande DROP TABLE dans une variable définie par l'utilisateur.

SELECT CONCAT('DROP TABLE ',GROUP_CONCAT(DBTB),';')
INTO @DropCommand
FROM (SELECT CONCAT(table_schema,'.',table_name) DBTB
FROM information_schema.tables
WHERE table_rows = 0 AND table_schema NOT IN
('information_schema','mysql','performance_schema')) A;
SELECT @DropCommand;

Si la sortie du SELECT @DropCommand;est correcte, exécutez la commande comme ceci:

PREPARE s FROM @DropCommand;
EXECUTE s;
DEALLOCATE PREPARE s;

Cela élimine deux choses:

  • la nécessité d'un fichier texte SQL externe
  • exécuter une commande DROP TABLE distincte pour chaque table
RolandoMySQLDBA
la source
1
Merci pour une longue et bonne explication! +1 pour le retour des tables dans les bases de données. De cette façon, il est facile de nettoyer plusieurs jeux de données. D'autre part; utiliser avec précaution. J'exécute votre requête contre "..AND table_schema = 'my_database_name'" pour ne travailler qu'avec une seule base de données (comme Tom Desp l'a suggéré dans une autre réponse)
qualbeen