Taking the suggestion by @usr to avoid recursive CTEs, I came up with the following formulation:
WITH R4 AS (
SELECT col FROM (VALUES (1), (2), (3), (4)) x(col)
), R16 AS (
SELECT a.col
FROM R4 AS a CROSS JOIN R4 AS b
), R100 AS (
SELECT TOP 100 ROW_NUMBER() OVER (ORDER BY a.col) AS n
FROM R16 AS a CROSS JOIN R16 AS b
)
SELECT CASE
WHEN n % 15 = 0 THEN 'FizzBuzz'
WHEN n % 3 = 0 THEN 'Fizz'
WHEN n % 5 = 0 THEN 'Buzz'
ELSE CAST(n AS NVARCHAR(8))
END AS FizzBuzz
FROM R100
ORDER BY n;
I've found that SQL Fiddle is a poor benchmarking platform, as execution times there are completely erratic. Since you want to run this on MS SQL Server, though, we can use Stack Exchange Data Explorer. ☺
Here's your original query and the my non-recursive formulation. Both take 3 ms on Stack Exchange Data Explorer when the results are not cached.