When you use SQL, how do you write delete statements at the database prompt?
A delete statement typically looks like this:
delete from table_name where column_name = 'foo';. I usually write it in this order:
delete where column_name = 'foo';
delete from table_name where column_name = 'foo';
Even though this is a pain because you have to move back and forth (I really need to look into vi keybindings for mysql), it prevents you from making sending this command by accident:
delete from table_name; which deletes all the data in your table. (Another alternative is to never use the interactive client and always write out your delete statements in a file and run that file to delete data.)
But, recently, I did exactly that, because I forgot. I deleted all the data from one table in our production database. It was billing data, so rather important. Luckily, I am using Amazon RDS and had set up backup retention.
I wanted to outline what I did to recover from this.
- I took a deep breath.
- I wrote a message on the slack channel documenting what had happened and the possible customer impact.
- Depending on which data is removed, it’s possible you will want to put the application in maintenance mode and/or inform your customers of the issues. What I deleted was used rarely enough that I didn’t have to take these steps.
- I looked at how to restore an Amazon RDS backup.
- I restored the missing data.
- I communicated that things were back to normal to internal stakeholders.
Unfortunately, it wasn’t clear how to restore a single table. I’m used to being able to download a .sql file and hand edit it, but that’s not an option. Stackoverflow wasn’t super helpful. But if there’s anytime you want clarity, it’s when you are restoring production data. You don’t want to compound the problem by screwing up something else.
So, here’s how to restore a single table from an Amazon RDS backup:
- Note the time just before you deleted the data. (Another reason the slack message is nice. chatops ftw.)
- Start up another instance from that moment. I named it something obvious like ‘has-data-from-tablename’.
- Twiddle your thumbs anxiously while the new instance starts up.
- The instance is put into your default security group (as of this writing) which probably doesn’t allow mysql access. Make sure you modify this security group to allow access.
- When the instance is up, do a dump of the table you need:
mysqldump -t --ssl-ca=./amazon-rds-ca-cert.pem -u user -ppassword -h has-data-from-tablename.c1m7x25w24qor.us-east-1.rds.amazonaws.com -P3306 database_name tablename > restore-table_name.sql;(
-tomits the create database/table statements.)
- If your table is has had writes since you deleted everything, you may need to manually pull down the current data from the production system and merge it into
restore-table_name.sql;I was able to avoid this step.
- Load the data using mysql
mysql --ssl-ca=./amazon-rds-ca-cert.pem -u user -ppassword -h production.c1m7x25w24qor.us-east-1.rds.amazonaws.com -P3306 database_name < restore-table_name.sql;
- Review to make sure the data is correct.
- Test the application.
- Update the slack channel, and do any other notifications you need to (customers, internal contacts, etc).
- Revoke the default security group access you allowed above.
- Delete the ‘has-data-from-tablename’ instance.
Note this only works if you caught your mistake within the backup retention window. (Make sure you set that up.) We aren’t multi AZ or clustered, so I’m not sure how that would affect things.
Happy deep breathing!