Como descartar tabelas vazias

11

É possível descartar todas as tabelas vazias do meu enorme banco de dados (mysql)?

Estou procurando um comando sql para remover automaticamente todas essas tabelas vazias.

Atualmente, tenho 305 tabelas no meu conjunto de dados e cerca de 30% delas são tabelas vazias antigas, que não serão usadas no meu novo aplicativo.

Só para esclarecer; Todas as tabelas são do tipo = MyISAM

qualbeen
fonte
11
Todas as tabelas são MyISAM, InnoDB ou uma mistura de ambas ???
RolandoMySQLDBA
São todos MyISAM
qualbeen

Respostas:

11

A idéia provavelmente seria procurar as tabelas vazias usando INFORMATION_SCHEMA.TABLES

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

Em seguida, você poderá produzir uma consulta SQL com

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

Rápido e um pouco sujo, mas deve realmente funcionar.

Tom Desp
fonte
3
... e então você tem um servidor de banco de dados quebrado porque "provavelmente" excluiu algumas das tabelas do sistema mysql ... além do fato de o seu CONCAT produzir uma lista de tabelas sem referência ao esquema.
Cristian Porta
11
Você também tem o "direito" de adicionar inteligentemente restrições de banco de dados às suas tabelas, achei óbvio.
Tom Desp
3
a resposta não deve ter nada como garantido, porque a resposta é potencialmente perigosa para o usuário ... só isso #
Cristian Porta
2
+1 para configurar um único comando DROP TABLE.
RolandoMySQLDBA
11
@CP: Ok, entendi, meu erro terrível, por isso editei a resposta. A propósito, estou um pouco surpreso que uma consulta SQL possa realmente soltar uma tabela interna do sistema MySQL. Da minha perspectiva, isso está totalmente quebrado.
Tom Desp
7

Como todas as tabelas são MyISAM, isso facilita minha expressão.

Primeiro, você precisa consultar o INFORMATION_SCHEMA para as tabelas que possuem zero linhas:

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

Em seguida, formule a consulta para descartar as tabelas vazias:

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');

Agora, despeje os comandos em um arquivo de texto SQL externo.

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

Veja o conteúdo com um dos seguintes

  • less DropTables.sql
  • cat DropTables.sql

Se você estiver satisfeito com seu conteúdo, execute o script:

mysql -uroot -p < DropTables.sql

ou faça o login no mysql e execute-o assim:

mysql> source DropTables.sql

De uma chance !!!

CAVEAT : Esta técnica funciona apenas com a tabela MyISAM porque a contagem de linhas de uma tabela MyISAM é fisicamente armazenada nas .MYDtabelas. A tabela de metadados INFORMATION_SCHEMA.TABLES está sempre lendo isso e atualizando. NÃO TENTE ISTO COM INNODB !!!

ATUALIZAÇÃO 05-02-2014 11:46 EST

Há uma razão pela qual eu excluí ('information_schema','mysql','performance_schema')

O mysqlesquema possui tabelas vazias. Alguns MyISAM, alguns InnoDB, alguns CSV.

Por exemplo, aqui estão minhas tabelas no esquema mysql para MySQL 5.6.15 na minha área de trabalho

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>

Se algumas dessas mesas estavam a desaparecer (como columns_priv, proc_priv, tables_priv, etc.), o mecanismo de subvenção pode não funcionar corretamente ou pode causar mysqld não iniciar. Você também não quer bater o mysql.proc, pois é o lar físico dos Procedimentos Armazenados. Outros mecanismos podem não funcionar, caso você queira usá-los, como CrashSafe Replication, usando as tabelas InnoDB dentro do esquema mysql, ou se desejar inserir informações de fuso horário.

ATUALIZAÇÃO 05-02-2014 12:36 EST

Gostaria de felicitar Tom Desp por sua resposta por um motivo específico: sua sintaxe pode ser eliminada sem o uso de um script externo . Usando sua ideia, deixe-me capturar o comando DROP TABLE em uma variável definida pelo usuário.

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;

Se a saída do SELECT @DropCommand;estiver correta, execute o comando da seguinte maneira:

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

Isso elimina duas coisas:

  • a necessidade de um arquivo de texto SQL externo
  • executando um comando DROP TABLE separado para cada tabela
RolandoMySQLDBA
fonte
11
Obrigado por uma explicação longa e boa! +1 para retornar tabelas entre bancos de dados. Dessa forma, é fácil limpar vários conjuntos de dados. Por outro lado; use com cuidado. Eu executo sua consulta no "..AND table_schema = 'my_database_name'" para trabalhar apenas com um banco de dados (como Tom Desp sugeriu em outra resposta)
qualbeen