Watching blocks fill up in real time as they are being mined made me realize that miners are hashing a block that is (potentially) changing every second. Especially when there aren't enough transactions to fill up a block. So does this mean that, say in the case when transactions in the mempool are low, each time a new transaction enters the mempool the miners will stop attempting to hash the old block and start attempting to hash the new block that includes the new transaction? It seems like trying to shoot a moving target would really slow down the process... but I am not a programmer or a developer of any sort
It depends. There is almost practically no penalty to change the merkle hash of the block since miners should be fast enough to include an alternative merkle root as required. The server may request for the workers to change out the merkle root periodically through mining.notify on stratum for example.
Miners can include any transactions as they wish and it is not a necessity for them to discard the current block and include new transactions whenever they see anything.
Also I have noticed a handful of really small blocks that get mined especially fast. Is this just a coincidence that my lizard brain makes a connection, or is there some causality there?
No. The chances of you getting a valid block is not affected by the number of transactions or the size of the block. It's common for blocks to be mined within a few seconds of each other as some miners either don't include transactions at all after seeing a valid block on the network (to avoid the risk of including conflicting transactions, while they are validating the blocks) or if the miners are just slow at including transactions in the block.
Small like... empty? Probably empty blocks could be solved more easily, due to the fact that there's less information to be hashed each time.
It's the same.