Your solution, although a WHILE
loop, is essentially still a cursor in the sense that you loop over a number of records and execute one or more statements once for each record. It's not the WHILE
loop in itself, but rather the coding pattern where you loop over rows in a table and execute a statement for each row. Typically, "traditional" programming languages are row-based - this is the main difference between SQL and, for instance, C#, VBA, etc.
Why your query performs better with table variables may depend on a number of potential factors that we can't deduct from your question.
What you want to do when you're eliminating cursor-based solutions is to turn them into set-based solutions. Here's a very primitive pseudo-example:
DECLARE @sum int, @val int;
DECLARE cur CURSOR FOR SELECT val FROM table;
OPEN cur;
FETCH NEXT FROM cur INTO @val;
WHILE (@@FETCH_STATUS=0) BEGIN;
SET @sum=@sum+@val;
FETCH NEXT FROM cur INTO @val;
END;
CLOSE cur;
DEALLOCATE cur;
SELECT @sum AS grantTotal;
.. is equivalent to the following set-based query:
SELECT SUM(val) AS grandTotal FROM table;
In the first query, we loop over a table, row-by-row. In the second query, the entire calculation is done with the entire table as a single "set", i.e. set-based. Obviously, most cursor-based patterns will be a lot more complex, particularly if they launch a stored procedure for each row in the cursor. There isn't a single trick for how to convert a cursor-based solution to set-based one.
WHILE
loop was still a cursor and I guarantee you can get your cursor to operate at the same speed. See this post.