The database will send the results through some sort of stream. The exact details of this are abstracted so that the code one layer higher up doesn't need to care whether it's a network stream, a named pipe, or something else, but it's some sort of stream.
Moving things along a stream takes time. A lot more time to move a massive recordset of 2million rows along a network stream from a computer on the other side of the world than a recordset of one row from an in-memory stream on the same computer, but time either way.
Rather than wait for all of the data to come across, .Next()
will read enough bytes to build the next row of data. Possibly this data is already sitting in a buffer in memory because it's been read from the stream, possibly this means waiting for the data to come over the connection.
When you've called .Next()
3 times on a massive recordset, and made use of the results, there could still be data coming over the wire, so you can see how this can be good for making everything as efficient as possible. At this point perhaps the stored procedure is also still working, but most likely it's finished and the database per se is done with the query, but the part of it that handles connection still has a buffer full of results to send on.
After that the connection will still be open anyway. It will be open until you close it (whether explicitly or by coming to the end of a using
block). You are free to use it again with another query.
After you close the SqlConnection
object, the actually connection to the database will probably still be open, because pooling those connections is normally cheaper than creating a new one every time. https://stackoverflow.com/a/3845924/400547 explains this part of it a bit more.