I think the reason is because you have not enough data in your tables, so SQL Server does not chooses the BEST plan, it chooses Good Enough plan to execute your query.
I try following
create table #a (a int not null, primary key (a asc))
create table #b (b int not null, primary key (b asc))
create table #c (c int not null, primary key (c asc))
insert into #a (a)
select h+10*g
from
(values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))g(g)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))h(h)
insert into #b (b)
select a from #a where a % 5 > 0
insert into #c (c)
select a from #a where a % 4 > 0
Now if I run
select *
from #a a
inner join #b b on a = b
inner join #c c on a = c
Here is the execution plan
If I use merge join hint I get the following execution plan.
select *
from #c c
inner merge join #a a on a = c
inner merge join #b b on a = b
So it is clear that merge join will be better in this case. Estimated subTree cost is less for the query with merge joins, but both this queries are fast enough, there both do only 12 logical reads, so SQL Server decides that NESTED LOOP join is also good solution.
Not let add more data to our tables.
create table #a (a int not null, primary key (a asc))
create table #b (b int not null, primary key (b asc))
create table #c (c int not null, primary key (c asc))
insert into #a (a)
select h+10*g + 100*f + 1000*e+ 10000*z + 100000*y + 1000000*x
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))x(x)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))y(y)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))z(z)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))e(e)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))f(f)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))g(g)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))h(h)
insert into #b (b)
select a from #a where a % 5 > 0
insert into #c (c)
select a from #a where a % 4 > 0
Now we have 10mln data in #a, 8mln in #b and 6mln in #c. If I run the original query without any hints I get merge joins as expected.
select *
from #a a
inner join #b b on a = b
inner join #c c on a = c
If one join input is small (fewer than 10 rows) and the other join input is fairly large and indexed on its join columns, an index nested loops join is the fastest join operation because they require the least I/O and the fewest comparisons.
If the two join inputs are not small but are sorted on their join column (for example, if they were obtained by scanning sorted indexes), a merge join is the fastest join operation.
Hash joins can efficiently process large, unsorted, nonindexed inputs.
Advanced Query Tuning Concepts
LOOP, HASH and MERGE Join Types
Understanding SQL Server Physical Joins