├── README.markdown └── split-mysql-dump.rb /README.markdown: -------------------------------------------------------------------------------- 1 | What is it? 2 | =========== 3 | 4 | A simple script that splits a MySQL dump into lots of smaller files. 5 | It works both with data definitions and data only dumps. 6 | 7 | Usage: 8 | ------ 9 | 10 | First you need a mysqldump file, put it into the directory you want 11 | all the split files in: 12 | 13 |
14 | $ ruby split-mysql-dump.rb db.sql 15 | Found a new db: app 16 | Found a new table: administrator_log 17 | writing line: 229 200.494MB in 4 seconds 50.124MB/sec 18 | 19 | Found a new table: auth_strings 20 | writing line: 239 205.482MB in 6 seconds 34.247MB/sec 21 |22 | 23 | Alternatively, you can pipe in via STDIN in using '-s'. Great 24 | for working with large gzipped backups: 25 | 26 |
27 | $ gunzip -c db.sql.gz | ruby split-mysql-dump.rb -s 28 |29 | 30 | You can also limit the dump to particular tables using '-t' 31 | or exclude tables using '-i'. 32 | 33 |
34 | $ ruby split-mysql-dump.rb -t auth_strings, administrator_log db.sql 35 |36 | 37 | and 38 | 39 |
40 | $ ruby split-mysql-dump.rb -i auth_strings 41 |42 | 43 | When you're done you should have lots of files like this: 44 | 45 |
46 | -rw-r--r-- 1 rip rip 210233252 May 17 18:06 administrator_log.sql 47 | -rw-r--r-- 1 rip rip 215463582 May 17 18:06 auth_strings.sql 48 |49 | 50 | The first bit of the files will be the database that the tables are in 51 | based on the _USE_ statements in the dump. 52 | 53 | Contact: 54 | -------- 55 | You can contact me on rip@devco.net or follow my blog at http://www.devco.net I am also on twitter as ripienaar 56 | 57 | -------------------------------------------------------------------------------- /split-mysql-dump.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'optparse' 4 | 5 | tables = [] 6 | ignore = [] 7 | use_database = nil 8 | dumpfile = "" 9 | 10 | cmds = OptionParser.new do |opts| 11 | opts.banner = "Usage: split-mysql-dump.rb [options] [FILE]" 12 | 13 | opts.on("-s", "Read from stdin") do 14 | dumpfile = $stdin 15 | end 16 | 17 | opts.on("-t", '--tables TABLES', Array, "Extract only these tables") do |t| 18 | tables = t 19 | end 20 | 21 | opts.on("-i", '--ignore-tables TABLES', Array, "Ignore these tables") do |i| 22 | ignore = i 23 | end 24 | 25 | opts.on("-u", '--use-database NAME', String, "Assume NAME as database name") do |n| 26 | use_database = n 27 | end 28 | 29 | opts.on_tail("-h", "--help") do 30 | puts opts 31 | end 32 | 33 | end.parse! 34 | 35 | if dumpfile == "" 36 | dumpfile = ARGV.shift 37 | if not dumpfile 38 | puts "Nothing to do" 39 | exit 40 | end 41 | end 42 | 43 | STDOUT.sync = true 44 | 45 | class Numeric 46 | def bytes_to_human 47 | units = %w{B KB MB GB TB} 48 | e = self > 0 ? (Math.log(self)/Math.log(1024)).floor : 0 49 | s = "%.3f" % (to_f / 1024**e) 50 | s.sub(/\.?0*$/, units[e]) 51 | end 52 | end 53 | 54 | if File.exist?(dumpfile) 55 | if dumpfile == $stdin 56 | d = $stdin 57 | else 58 | d = File.new(dumpfile, "r:binary") 59 | end 60 | 61 | outfile = nil 62 | table = nil 63 | db = use_database 64 | linecount = tablecount = starttime = 0 65 | 66 | while (line = d.gets) 67 | # Detect table changes 68 | if line =~ /^-- Table structure for table .(.+)./ or line =~ /^-- Dumping data for table .(.+)./ or line =~ /^# Dump of table.(.+)/ 69 | is_new_table = table != $1 70 | table = $1 71 | 72 | # previous file should be closed 73 | if is_new_table 74 | outfile.close if outfile and !outfile.closed? 75 | 76 | puts("\n\nFound a new table: #{table}") 77 | 78 | if (tables != [] and not tables.include?(table)) 79 | puts"`#{table}` not in list, ignoring" 80 | table = nil 81 | elsif (ignore != [] and ignore.include?(table)) 82 | puts"`#{table}` will be ignored" 83 | table = nil 84 | else 85 | starttime = Time.now 86 | linecount = 0 87 | tablecount += 1 88 | path = (db.to_s == "" ? "" : "#{db}/") + "tables"; 89 | Dir.mkdir(path) unless File.exists?(path) 90 | outfile = File.new("#{path}/#{table}.sql", "w") 91 | outfile.syswrite("USE `#{db}`;\n\n") 92 | end 93 | end 94 | elsif line =~ /^-- Current Database: .(.+)./ 95 | db = $1 96 | table = nil 97 | outfile.close if outfile and !outfile.closed? 98 | Dir.mkdir(db) 99 | Dir.mkdir("#{db}/tables") 100 | outfile = File.new("#{db}/create.sql", "w") 101 | puts("\n\nFound a new db: #{db}") 102 | elsif line =~ /^-- Position to start replication or point-in-time recovery from/ 103 | db = nil 104 | table = nil 105 | outfile.close if outfile and !outfile.closed? 106 | outfile = File.new("1replication.sql", "w") 107 | puts("\n\nFound replication data") 108 | end 109 | 110 | # Write line to outfile 111 | if outfile and !outfile.closed? 112 | outfile.syswrite(line) 113 | linecount += 1 114 | elapsed = Time.now.to_i - starttime.to_i + 1 115 | print(" writing line: #{linecount} #{outfile.stat.size.bytes_to_human} in #{elapsed} seconds #{(outfile.stat.size / elapsed).bytes_to_human}/sec \r") 116 | end 117 | end 118 | end 119 | 120 | puts 121 | --------------------------------------------------------------------------------