{"id":2295,"date":"2016-12-11T14:38:39","date_gmt":"2016-12-11T20:38:39","guid":{"rendered":"http:\/\/www.mooreds.com\/wordpress\/?p=2295"},"modified":"2022-11-29T15:28:07","modified_gmt":"2022-11-29T21:28:07","slug":"restoring-a-single-table-from-an-amazon-rds-backup","status":"publish","type":"post","link":"https:\/\/www.mooreds.com\/wordpress\/archives\/2295","title":{"rendered":"Restoring a single table from an Amazon RDS backup"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-2296 alignright\" src=\"http:\/\/www.mooreds.com\/wordpress\/wp-content\/uploads\/2016\/09\/material-icon-1307676_640-300x300.png\" alt=\"material-icon-1307676_640\" width=\"300\" height=\"300\" srcset=\"http:\/\/edit.mooreds.com\/wordpress\/wp-content\/uploads\/2016\/09\/material-icon-1307676_640-300x300.png 300w, http:\/\/edit.mooreds.com\/wordpress\/wp-content\/uploads\/2016\/09\/material-icon-1307676_640-150x150.png 150w, http:\/\/edit.mooreds.com\/wordpress\/wp-content\/uploads\/2016\/09\/material-icon-1307676_640.png 640w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/>When you use SQL, how do you write delete statements at the database prompt?<\/p>\n<p>A delete statement typically looks like this: <code>delete from table_name where column_name = 'foo';<\/code>. I usually write it in this order:<\/p>\n<ol>\n<li><code>delete<\/code><\/li>\n<li><code>delete where column_name = 'foo';<\/code><\/li>\n<li><code>delete from table_name where column_name = 'foo';<\/code><\/li>\n<\/ol>\n<p>Even though this is a pain because you have to move back and forth (I really need to look into <a href=\"http:\/\/stackoverflow.com\/questions\/2216471\/how-to-get-vi-keybindings-to-work-in-mysql-client\">vi keybindings for mysql<\/a>), it prevents you from making sending this command by accident: <code>delete from table_name;<\/code> which deletes all the data in your table.\u00a0 (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.)<\/p>\n<p>But, recently, I did exactly that, because I forgot.\u00a0 I deleted all the data from one table in our production database.\u00a0 It was billing data, so rather important.\u00a0 Luckily, I am using Amazon RDS and had set up backup retention.<\/p>\n<p>I wanted to outline what I did to recover from this.<\/p>\n<ul>\n<li>I took a deep breath.<\/li>\n<li>I wrote a message on the slack channel documenting what had happened and the possible customer impact.<\/li>\n<li>Depending on which data is removed, it&#8217;s possible you will want to put the application in maintenance mode and\/or inform your customers of the issues.\u00a0 What I deleted was used rarely enough that I didn&#8217;t have to take these steps.<\/li>\n<li>I looked at how to restore an <a href=\"http:\/\/docs.aws.amazon.com\/AmazonRDS\/latest\/UserGuide\/CHAP_CommonTasks.BackupRestore.html\">Amazon RDS backup<\/a>.<\/li>\n<li>I restored the missing data.<\/li>\n<li>I communicated that things were back to normal to internal stakeholders.<\/li>\n<\/ul>\n<p>Unfortunately, it wasn&#8217;t clear how to restore a single table.\u00a0 I&#8217;m used to being able to download a .sql file and hand edit it, but that&#8217;s not an option.\u00a0 <a href=\"http:\/\/stackoverflow.com\/questions\/9815612\/should-i-stick-only-to-aws-rds-automated-backup-or-db-snapshots\">Stackoverflow wasn&#8217;t super helpful<\/a>. \u00a0 But if there&#8217;s anytime you want clarity, it&#8217;s when you are restoring production data.\u00a0 You don&#8217;t want to compound the problem by screwing up something else.<\/p>\n<p>So, here&#8217;s how to restore a single table from an Amazon RDS backup:<\/p>\n<ul>\n<li>Note the time just before you deleted the data.\u00a0 (Another reason the slack message is nice.\u00a0 <a href=\"https:\/\/victorops.com\/\">chatops<\/a> ftw.)<\/li>\n<li><a href=\"http:\/\/docs.aws.amazon.com\/AmazonRDS\/latest\/UserGuide\/USER_PIT.html\">Start up another instance<\/a> from that moment.\u00a0 I named it something obvious like &#8216;has-data-from-tablename&#8217;.<\/li>\n<li>Twiddle your thumbs anxiously while the new instance starts up.<\/li>\n<li>The instance is put into your default security group (as of this writing) which probably doesn&#8217;t allow mysql access.\u00a0 Make sure you <a href=\"http:\/\/docs.aws.amazon.com\/AmazonRDS\/latest\/UserGuide\/USER_WorkingWithSecurityGroups.html#USER_WorkingWithSecurityGroups.Authorizing\">modify this security group to allow access<\/a>.<\/li>\n<li>When the instance is up, do a dump of the table you need: <code>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 &gt; restore-table_name.sql;<\/code> (<code>-t<\/code> omits the create database\/table statements.)<\/li>\n<li>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 <code>restore-table_name.sql;<\/code>\u00a0I was able to avoid this step.<\/li>\n<li>Load the data using mysql <code>mysql --ssl-ca=.\/amazon-rds-ca-cert.pem -u user -ppassword -h production.c1m7x25w24qor.us-east-1.rds.amazonaws.com -P3306 database_name &lt; restore-table_name.sql;<\/code><\/li>\n<li>Review to make sure the data is correct.<\/li>\n<li>Test the application.<\/li>\n<li>Update the slack channel, and do any other notifications you need to (customers, internal contacts, etc).<\/li>\n<li>Revoke the default security group access you allowed above.<\/li>\n<li>Delete the &#8216;has-data-from-tablename&#8217; instance.<\/li>\n<\/ul>\n<p>Note this only works if you caught your mistake within the backup retention window. (Make sure <a href=\"http:\/\/docs.aws.amazon.com\/AmazonRDS\/latest\/UserGuide\/Overview.BackingUpAndRestoringAmazonRDSInstances.html\">you set that up<\/a>.)\u00a0 We aren&#8217;t multi AZ or clustered, so I&#8217;m not sure how that would affect things.<\/p>\n<p>Happy deep breathing!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 = &#8216;foo&#8217;;. I usually [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[79,39,13],"tags":[],"class_list":["post-2295","post","type-post","status-publish","format-standard","hentry","category-aws","category-cloud-computing","category-databases"],"_links":{"self":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2295"}],"version-history":[{"count":7,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2295\/revisions"}],"predecessor-version":[{"id":2303,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2295\/revisions\/2303"}],"wp:attachment":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}