@@ -224,31 +224,39 @@ end
224224 stream(ctx, sql; batch_size=10_000) → Channel{DataFrame}
225225
226226Execute `sql` and return a `Channel` that emits successive `DataFrame` batches.
227- Each batch has at most `batch_size` rows. The channel is closed automatically
228- when all rows have been consumed or when an error occurs.
227+ The channel is closed automatically when all rows have been consumed or when an
228+ error occurs.
229+
230+ The SQL is executed once and results are consumed via DuckDB's native chunk
231+ iterator, so streaming is O(N) regardless of result size.
232+
233+ Each batch contains at least `batch_size` rows (it may be slightly larger
234+ because whole DuckDB-internal chunks of ~2048 rows are accumulated before
235+ emitting).
229236
230237```julia
231238for batch in stream(ctx, "SELECT * FROM huge_table"; batch_size=5_000)
232239 process(batch)
233240end
234241```
235-
236- !!! note
237- The SQL is wrapped in a sub-query with `LIMIT … OFFSET …` which requires the
238- query engine to re-execute the underlying plan for each batch. For best
239- performance on very large scans, consider using DuckDB's native export or
240- `COPY` instead.
241242"""
242243function stream (ctx:: QueryContext , sql:: String ; batch_size:: Int = 10_000 ):: Channel{DataFrame}
243244 Channel {DataFrame} (2 ) do ch
244- offset = 0
245- while true
246- batch_sql = " SELECT * FROM ($sql ) AS __stream_q__ LIMIT $batch_size OFFSET $offset "
247- batch = execute (ctx, batch_sql)
248- nrow (batch) == 0 && break
249- put! (ch, batch)
250- offset += batch_size
251- nrow (batch) < batch_size && break
245+ _with_conn (ctx) do conn
246+ result = DuckDB. execute (conn, sql)
247+ pending = DataFrame[]
248+ pending_rows = 0
249+ for chunk in Tables. partitions (result)
250+ chunk_df = DataFrame (chunk)
251+ push! (pending, chunk_df)
252+ pending_rows += nrow (chunk_df)
253+ if pending_rows >= batch_size
254+ put! (ch, vcat (pending... ))
255+ empty! (pending)
256+ pending_rows = 0
257+ end
258+ end
259+ pending_rows > 0 && put! (ch, vcat (pending... ))
252260 end
253261 end
254262end
0 commit comments