I've made some test. I have two tables - tableA (~3000 rows) and tableB (~200 rows). both of them has column id. TableA: ID - pk, TableB: ID - fk, non-clustered index.
Select from one table:
SELECT
a.ID
FROM
dbo.TableA a
WHERE
a.ID IN (1,5,7,9,23,45,56,546,67,32,54,676)
-- EXECUTION PLAN:
|--Index Seek(OBJECT:([Database].[dbo].[TableA].[IX_TableA_ID] AS [a]), SEEK:([a].[ID]=(1) OR [a].[ID]=(5)) ORDERED FORWARD)
-- STATISTICS IO:
Table 'TableA'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Select using two tables (inner join)
SELECT
t.ID
FROM
dbo.TableA a
INNER JOIN
dbo.TableB t with(index(PK_TableBs)) ON t.ID = a.ID
WHERE
t.ID IN (1,5,7,9,23,45,56,546,67,32,54,676)
-- EXECUTION PLAN:
|--Nested Loops(Inner Join, OUTER REFERENCES:([t].[ID]))
|--Clustered Index Seek(OBJECT:([Database].[dbo].[TableB].[PK_TableB] AS [t]), SEEK:([t].[ID]=(1) OR [t].[ID]=(5)) ORDERED FORWARD)
|--Index Seek(OBJECT:([Database].[dbo].[TableA].[IX_TableA_ID] AS [a]), SEEK:([a].[ID]=[Database].[dbo].[TableB].[ID] as [t].[ID]), WHERE:([Database].[dbo].[TableA].[ID] as [a].[ID]>=(1) AND [Database].[dbo].[TableA].[ID] as [a].[ID]<=(5)) ORDERED FORWARD)
-- STATISTICS IO:
Table 'TableA'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableB'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Result:
The second query cost is 67% (relative to the batch) against to the first query (33%).
Also, the second query requires more reads.
PS. This is dirty quick example, you shoud check your own.