Отправка файла обрабатывается операционной системой. Он просто запихивает содержимое в сокет и не требует дополнительных затрат от вашего приложения. Это буквально огонь и забыть.
Отправка потока данных с сервера базы данных значительно сложнее. Запрос должен быть составлен, закодирован, отправлен через сокет, интерпретирован сервером, выполнен, а набор результатов должен быть перекодирован и отправлен обратно по проводам. Может быть, вы вычитаете это время из своего расчета, но это не ясно.
Затем, как только клиент получил результат, он должен прочитать его из сокета, преобразовать его в объекты Ruby, возможно, в модели, которые несут еще больше накладных расходов, и передать этот объект результата обратно запрашивающему методу. Если вы затем повторно сериализуете его в результат, он должен пройти процесс повторного копирования этих данных в выходной поток.
Итак, в итоге, чтение из существующего файла: ноль считываний, ноль копий.
Чтение из базы данных: одно чтение, две копии.