Yes! global state seems the best way to track the highest bid.
That is a bit trickier! 20.000 bids would rule out the use of global state to track everything, so I think you would have to use the indexer with one of 2 approaches:
-
Store the information in user local storage and query it through the indexer, as you mention above
-
Iterate through the actual transactions sent to the contract with the indexer, looking for new bids
The difference in runtime will come from: reading from user local state (1) as opposed to parsing transactions of a certain address (2). If I had to guess, I would expect the second approach to be faster! But, you should always test!