One compute-intensive part of the server work is creating new merkle roots. As mckoss mentions this becomes a lot faster if you only recalculate the merkle branch that is changed by the new generation transaction instead of recalculating the entire merkle tree.
The other compute-intensive part of the server's job is verifying the proofs of work that are later sent in. In general this means hashing two SHA-256 chunks and verifying the result against the difficulty. But if there are multiple proofs of work with the same merkle root then you could calculate the midstate once, and then just hash one SHA-256 chunk for each proof of work you want to verify. Just like clients do with rollntime.
So every new merkle root is work to generate, and also creates more work later by needing a new midstate to be calculated.
BitMinter makes use of rolling the ntime field on the server as well as in the client. Every time the wall clock ticks forward one second, you update the ntime field of the block data with a new timestamp. Then you can reuse all the merkle roots and midstates you have from the previous second.
This saves a massive amount of work on the server, and it is how BitMinter could run with low load on a single server with 2-3 TH/s of hashpower while some (not well optimized) pools needed a new server for every 300 GH/s of hashpower.
Since then such optimizations have become less important. More clients started supporting rollntime. Servers and clients started using work difficulty above 1, meaning much less work had to be verified on the server. And then there are the new protocols to replace getwork: Stratum and GBT (getblocktemplate). With these protocols the server just generates a template which is very cheap to generate, then the clients do the heavier part of creating work based on the template.
I still think it's a good idea for clients to use the ntime trick to reuse merkle roots and midstates, which allows midstate reuse on the server side as well, although this is no longer a big deal.