It is not just the STLINK; it is also the Cube IDE code which talks to it. I have no idea how that is organised.
Logically one would implement simple RLL encoding, so 900kbytes of 0xFF doesn't have to get sent

But that 900k still needs to get written at the target end, and if you do it with a pre-read then that 900k can be done very fast. I am fairly sure Cube+STLINK does that much.
One difference is the "Segger process" emits way more text into the console, and this includes stuff like erasing whole blocks. On the 32F417 these blocks vary from 16k to 128k and to use this feature you obviously need to "scan ahead" at the PC end and if e.g. the top 128k is all 0xFF (quite a likely scenario) then you can just send a block erase command. My boot loader uses these block erase commands and they are fairly quick.
Currently I am loading ~600k of code and if one changes e.g.
int fred=5 to
int fred=6
then the rest of the 600k block does not change, and that is where the Segger is much faster. How relevant that is to reality, I don't know.