Skip to content

Instantly share code, notes, and snippets.

@wvanbergen
Created August 22, 2010 11:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wvanbergen/543686 to your computer and use it in GitHub Desktop.
Save wvanbergen/543686 to your computer and use it in GitHub Desktop.
Convert InnoDB tables to use a separate idb files instead of the shared, giant ibdata1.
#!/usr/bin/env ruby
# Converts an InnoDB database that uses a shared InnoDB tablespace file (e.g. ibdata1) to use
# a separate file per table.
#
# - First change your my.cnf file to use separate files by adding "innodb_file_per_table" to
# the [mysqld] section. (This is safe: MySQL will revert to the giant file if it cannot find
# the per table file.)
# - Restart the MySQL server
# - cd to the directory of your database (cd /opt/mysql/data/mydb)
# - Run this script from that directory
#
# This script will run ALTER TABLE name ENGINE=InnoDB for all your tables that are not yet converted.
# This will move the data of that table to a separate idb file and this can take quite some time.
# You can interrupt this script at any time; restarting it will resume the operation. The database
# will remain functional (albeit slow) at all times)
#
# After you have converted *ALL* databases into using separate ibd files, you can remove the
# ibdata1 files (and ibdata2, ibdata3, ...)
require 'rubygems'
require 'mysql2'
require 'benchmark'
frm_files = Dir['./*.frm'].map { |file| File.basename(file, '.frm') }
idb_files = Dir['./*.ibd'].map { |file| File.basename(file, '.ibd') }
current_database = File.basename(Dir.pwd)
unconverted_tables = frm_files - idb_files
if unconverted_tables.size > 0
client = Mysql2::Client.new(:host => 'localhost', :username => 'root', :database => current_database)
if idb_files.empty?
puts "Starting conversion of #{current_database} database."
else
puts "Resuming conversion of #{current_database} database."
end
puts " Tables to convert: "
puts "- " + unconverted_tables.join("\n- ")
puts
unconverted_tables.each do |table|
print "Converting table #{table}..."
$stdout.flush
duration = Benchmark.realtime { client.query("ALTER TABLE #{table} ENGINE=InnoDB") }
puts ' Done in %0.2fs!' % duration
end
puts "Finished conversion!"
else
puts "#{current_database} database already completely converted."
end
@mosesjohann
Copy link

Hello! Found this and wanted to run after installing a few dependencies on my Ubuntu 12.04.5 chrooted. I run into an error then:

Converting table time_zone_name.../var/lib/gems/1.8/gems/mysql2-0.4.5/lib/mysql2/client.rb:125:in _query': Storage engine 'InnoDB' does not support system tables. [mysql.time_zone_name] (Mysql2::Error) from /var/lib/gems/1.8/gems/mysql2-0.4.5/lib/mysql2/client.rb:125:in \query'
from ./convert_innodb_to_per_table_ibd.rb:47
from /usr/lib/ruby/1.8/benchmark.rb:308:in `realtime'
from ./convert_innodb_to_per_table_ibd.rb:47
from ./convert_innodb_to_per_table_ibd.rb:44:in `each'
from ./convert_innodb_to_per_table_ibd.rb:44

@NealBozeman
Copy link

On mysql5.5, if you run this, the tables convert, but when you rm ibdata1 and ib_logfile0, etc, then do a mysql restart, your DB will become corrupted. The meta data saved in ibdata1 is now lost. Isn't this also the case on higher versions of MySQL, up to 5.7?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment