Promoting a slave would probably be my preferred route. As you pointing out any selects on MyISAM tables would require table level locks. There is one tool that might be able to help, pt-table-sync. It's primary purpose is to find gaps and differences in existing master slave relationships.
A nice thing about it is it does this in nice "chunks". Think of it kind of like antilock breaks. The chunk size is configurable but you could, for example go through doing 1000 rows at a time, minimizing lock times and letting things flow through. I haven't used it to fully repopulate a slave from scratch though although I'd give that a look. Once you have a full copy, do another run to catch new stuff, updates that have come in. Do a flush table with read locks, do a final table sync. run show master status to get the binary log position to start slaving from, unlock tables.
Oh, if you don't have binary logging you'll at least need a master bounce and cnf change unfortunately.
Another approach that might be much simpler depending your write downtime tolerance. You're all myisam, you gave the size in rows by what's the disk footprint in MB or GB? Figure out how long it would take to transfer that size between your machines (hopefully there both in the same local network). You could do flush table with readlock, again still show master status, then just rsync the .MY* files over to your new DB's datadir.
One final alternative, depending on how you're setup: Can you do an LVM or other kind of filesystem snapshot? This would be the best way to minimize downtime. You flush tables with readlock, show master status, start snapshot, then unlock the tables to allow full read write activity to flow through. The difference here is you'll copy the snapshot you started. You'll just need to feel confident the write activity won't exceed the snapshot size you allocate before the copy finishes.
What ever method, before promotion I would verify the character set conversions went as desired. They can be a real pain to reverse.
I would also recommend upgrading to innodb if possible to make it possible to use xtrabackup in a non blocking fashion in the future.
MySQL's documentation for utf8 shows that it will use 1 byte for Latin characters, and only use more if the situation requires them.
Therefore, if you're only using normal latin characters, both utf8_general_ci and latin1_general_ci will use between 1 and 4 bytes: one byte to store the length (0-3 characters), and then up to three bytes for the actual text.
If the value of this field will always be exactly three characters, you could save one byte by changing the column from a varchar(3)
to a char(3)
(as long as you also use latin1_general_ci
).
If it's not exactly three characters, it's likely to be more efficient to leave it as a varchar
- there's not much more you can do to reduce the size of this field. However, with a 40GB table you can hopefully find something else to optimise!
Best Answer
I found an answer on this website: http://kb.siteground.com/article/How_to_change_the_collation_for_all_tables_in_db_to_UTF8.html
I cleaned up the code to print out better from a linux shell and added the $new_charset and $new_collation variables to the alter database statement.
I tested the answer on my own database changing from charset latin7 to latin1 and latin7_general_cs to latin1_general_cs for the collation.
I chose _cs instead of _ci for the collation because if you choose _ci which is the default collation for charset latin_1, the collation no longer shows up in the show create table tablename column output.
Try it out
You can see all of the available charsets and their corresponding collations with the show collation sql query