I'd like to make a third table that has the same structure as the second, but with only those rows for which the 'from' and 'to' IDs are in the first table.
This is referred to as "denormalization" and while there are valid reasons to do it, it's not considered good database design and should be avoided.
Presumably you want to do this because your queries are so slow. So let's look at your query.
SELECT *
FROM table2
WHERE from_id IN (SELECT id FROM table1)
AND to_id IN (SELECT id FROM table1)
This might be slow if MySQL has to do a full table scan of table1, but it appears to be smart enough to recognize it can use an index.
mysql> explain SELECT * FROM table2 WHERE from_id IN (SELECT id FROM table1) AND to_id IN (SELECT id FROM table1);
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
| 1 | SIMPLE | table2 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 1 | SIMPLE | table1 | eq_ref | PRIMARY | PRIMARY | 4 | test.table2.from_id | 1 | Using index |
| 1 | SIMPLE | table1 | eq_ref | PRIMARY | PRIMARY | 4 | test.table2.to_id | 1 | Using index |
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
3 rows in set (0.00 sec)
I think it can be expressed better by explicitly asking for the exact ID in a sub query.
SELECT t2.*
FROM table2 t2
WHERE (SELECT 1 FROM table1 t1 WHERE t1.id = t2.from_id)
AND (SELECT 1 FROM table1 t1 WHERE t1.id = t2.to_id)
mysql> explain SELECT t2.* FROM table2 t2 WHERE (SELECT 1 FROM table1 t1 WHERE t1.id = t2.from_id) AND (SELECT 1 FROM table1 t1 WHERE t1.id = t2.to_id);
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
| 1 | PRIMARY | t2 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 3 | DEPENDENT SUBQUERY | t1 | eq_ref | PRIMARY | PRIMARY | 4 | test.t2.to_id | 1 | Using index |
| 2 | DEPENDENT SUBQUERY | t1 | eq_ref | PRIMARY | PRIMARY | 4 | test.t2.from_id | 1 | Using index |
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
3 rows in set (0.00 sec)
It's hard to say which one will be faster, I don't have your data set. So long as table2.from_id, table2.to_id and t1.id are indexed, and they should be so long as they're properly declared as foreign and primary keys, you should be ok.
If it's still not fast enough, instead of denormalizing I would suggest you create a view or a temporary table or a query cache. These can effectively cache the query without having to denormalize. Which you choose depends on how often your data updates and how sensitive your application is to changes.