Как отбрасывать пустые таблицы

11

Можно ли удалить все пустые таблицы из моей огромной базы данных (mysql)?

Я ищу команду sql для автоматического удаления всех этих пустых таблиц.

В настоящее время у меня есть 305 таблиц в моем наборе данных, и около 30% из них - старые пустые таблицы, которые не будут использоваться в моем новом приложении.

Чтобы уточнить; Все таблицы имеют тип = MyISAM

qualbeen
источник
1
Все ли таблицы MyISAM, InnoDB или смесь обоих ???
RolandoMySQLDBA
Все они - MyISAM
до

Ответы:

11

Идея, вероятно, будет искать пустые таблицы, используя INFORMATION_SCHEMA.TABLES

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

Тогда вы сможете создать SQL-запрос с

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

Быстро и немного грязно, но на самом деле должно работать.

Том Десп
источник
3
... а затем у вас сломан сервер базы данных, потому что вы "вероятно" удалили некоторые из системных таблиц mysql ... кроме того факта, что ваш CONCAT создает список таблиц без ссылки на схему.
Кристиан Порта
1
У вас также есть «право» разумно добавлять ограничения базы данных к вашим таблицам, я думал, что это очевидно.
Том Десп
3
ответ не должен принимать что-либо как должное, потому что ответ потенциально опасен для пользователя ... вот и все
Кристиан Порта
2
+1 за настройку одной команды DROP TABLE.
RolandoMySQLDBA
1
@CP: Хорошо, я понял, моя ужасная ошибка, поэтому я отредактировал ответ. Кстати, я немного удивлен, что SQL-запрос может фактически удалить внутреннюю таблицу системы MySQL. С моей точки зрения, это полностью сломано.
Том Десп
7

Поскольку все таблицы являются MyISAM, это облегчает мой ответ.

Сначала вам нужно запросить у INFORMATION_SCHEMA таблицы с нулевыми строками:

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

Далее, сформулируйте запрос, чтобы удалить пустые таблицы:

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

Теперь поместите команды во внешний текстовый файл SQL.

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

Посмотрите на содержимое с одним из следующих

  • less DropTables.sql
  • cat DropTables.sql

Если вас устраивает его содержимое, запустите скрипт:

mysql -uroot -p < DropTables.sql

или войдите в MySQL и запустите его так:

mysql> source DropTables.sql

Попробуйте!

CAVEAT : этот метод работает только с таблицей MyISAM, поскольку счетчик строк таблицы MyISAM физически хранится в .MYDтаблицах. Таблица метаданных INFORMATION_SCHEMA.TABLES всегда читает это и обновляет. НЕ ПЫТАЙТЕСЬ С INNODB !!!

ОБНОВЛЕНИЕ 2014-02-05 11:46 EST

Есть причина, по которой я исключил ('information_schema','mysql','performance_schema')

В mysqlсхеме есть пустые таблицы. Некоторые MyISAM, некоторые InnoDB, некоторые CSV.

Например, вот мои таблицы в схеме MySQL для MySQL 5.6.15 на моем рабочем столе

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>

Если некоторые из этих таблиц должны были исчезнуть (как columns_priv, proc_priv, tables_privи т.д.), механизм гранта не может работать неправильно или может привести к туздЫ не пускать. Вы также не хотите взломать mysql.proc, поскольку это физический дом хранимых процедур. Другие механизмы могут не работать, если вы захотите их использовать, например, CrashSafe Replication с использованием таблиц InnoDB внутри схемы mysql или если вы хотите вставить информацию о часовом поясе.

ОБНОВЛЕНИЕ 2014-02-05 12:36 EST

Я хотел бы поблагодарить Тома Деспа за его ответ по определенной причине: его синтаксис может выполнить отбрасывание без использования внешнего сценария . Используя его идею, позвольте мне записать команду DROP TABLE в пользовательскую переменную.

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;

Если выходные данные SELECT @DropCommand;правильные, выполните команду следующим образом:

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

Это устраняет две вещи:

  • необходимость внешнего текстового файла SQL
  • запуск отдельной команды DROP TABLE для каждой таблицы
RolandoMySQLDBA
источник
1
Спасибо за длинное и хорошее объяснение! +1 за возврат таблиц по базам данных. Таким образом, легко очистить несколько наборов данных. С другой стороны; используйте с осторожностью. Я запускаю ваш запрос к "..AND table_schema = 'my_database_name'", чтобы работать только с одной базой данных (как предложил Том Десп в другом ответе)
задано