Streaming
Streaming rows
queryS returns a Stream from the
streaming package instead
of a list. Rows are read from the socket as you pull them, so memory does
not grow with the size of the result:
import qualified Streaming.Prelude as S
s <- queryS conn "SELECT id, payload FROM dbo.big_table"
S.mapM_ (\(i :: Int64, p :: ByteString) -> process i p) sThe one rule#
Finish the stream before you make another request on the connection.
If you stop early and move on, the next request cancels the statement on
the server, and what was left is discarded. The old stream throws
ResultAbandoned if anything touches it again.
A connection going back to a pool gets the same treatment from release,
so the statement does not keep its locks while the connection waits in
the pool. A web server whose client hangs up mid-response is the usual
case.
On a MARS connection the rule is different: the next request leaves the stream open. MARS explains.
withQueryS#
withQueryS is queryS within a scope:
withQueryS conn "SELECT id, payload FROM dbo.big_table" $ \s ->
S.mapM_ (\(i :: Int64, p :: ByteString) -> process i p) sWhen the action ends, a stream that was not read to its end is canceled.
Whether the action returned or threw, the statement is over on the server
by the time withQueryS returns, and its locks are released.
On a MARS connection, prefer withQueryS. On a plain connection it works
too, under the rule above.
Interruptions#
A timeout around a stream read cancels the statement at once. The
stream throws ResultAbandoned afterwards, and the connection stays
usable.
The timeout returns at once, and the next request on the connection
finishes the cancel first. Until then the statement may still hold its
locks. To wait for them to go, call cancelActiveStatement conn.
Under SET XACT_ABORT ON, a canceled stream inside a transaction can
roll the transaction back.
Transactions has the details.
Streaming within a value#
A single large value can be streamed too, as chunks of one column, with
streamField.
Streaming values covers
it, together with streamed parameters and the generic cell interface.
How it works#
The server sends rows in packets, and hmssql decodes a packet’s rows when you pull them. The rest waits in the socket, so memory stays flat.
Canceling sends the server an Attention. The server stops the statement
and acknowledges. An ordinary exit from withQueryS waits for that
acknowledgment, while an interruption leaves it to the next request.