Here's the real problem: Normal SELECT statements against an InnoDB table will not lock any rows, but INSERT INTO...SELECT does. The easiest way around this is to first select the desired rows from the source table into a file, then import the file into the target table.
One way to do this:
SELECT... INTO OUTFILE, then LOAD DATA INFILE, e.g.:
Given this table:
mysql> select * from source_table;
+----+-----------+---------+----------+
| id | columnA | columnB | columnC |
+----+-----------+---------+----------+
| 1 | monkey | mammal | jungle |
| 2 | alligator | reptile | swamp |
| 3 | elephant | mammal | savannah |
+----+-----------+---------+----------+
3 rows in set (0.00 sec)
Extract columnA and columnB where columnC = 'swamp' and store the results in a file in the schema subdirectory:
mysql> select NULL, columna, columnB into outfile 'swampanimals.txt' from source_table where columnC='swamp';
The NULL there is a placeholder for the id column. It will be replaced with the auto_increment value when loaded later.
Then load the resulting file into the target table:
mysql> load data infile 'swampanimals.txt' into table target_table;
Assuming that target_table was empty to start with, it will look like this:
mysql> select * from target_table;
+----+-----------+---------+
| id | columnA | columnB |
+----+-----------+---------+
| 1 | alligator | reptile |
+----+-----------+---------+
1 row in set (0.00 sec)
Given that you're using RDS, may not be able to use SELECT...INTO OUTFILE -- I don't know about that. If you can't use it, you could do something like this instead:
mysql --host=<rdshost> -s -e "SELECT NULL, columnA, columnB FROM source_table WHERE columnC='swamp'" | sed -r "s/NULL/\\\N/" > swampanimals.txt
That sed is the only way I know to get the NULL into the output as a NULL character instead of as the literal string "NULL". Then you would use LOCAL when doing the load data infile:
mysql> load data local infile "swampanimals.txt" into table target_table;
One problem you might have, since you have two billion rows of data, is that the LOAD DATA INFILE could create a very large transaction and cause your ibdata file, which is where the undo logs are stored, to be stretched out. You can work around this by loading the data from the file in chunks. Here's a sweet trick for that, but it requires a modern version of split. Given a large input file called "bigfile" and loading it into the table "target_table" of schema "target_schema":
split -C100M --filter="mysql target_schema -e \"LOAD DATA LOCAL INFILE '/dev/stdin' INTO TABLE target_table\"" bigfile
That will break the file into 100 MB chunks, but chunks will not be split across lines. That way you wouldn't have any transactions > 100 MB in size and your undo logs wouldn't get stretched out.
Refer to: https://dev.mysql.com/doc/refman/5.6/en/select-into.html and https://dev.mysql.com/doc/refman/5.6/en/load-data.html for full details on SELECT...INTO OUTFILE and LOAD DATA INFILE.