Если вам нужны байты в массиве, то все методы в значительной степени будут одинаковыми, так как вы должны направить все байты из результирующего потока в массив (классы SqlClient собираются сделать это для вы).
Неважно, если у вас есть выходной параметр varbinary для хранимой процедуры или поле в таблице базы данных, хотя хранимая процедура будет немного быстрее, поскольку у вас нет информации схемы о наборе результатов, который нужно вернуть. Однако это незначительно по сравнению с размером данных, которые вы возвращаете.
Если вы действительно хотите повысить производительность, вам лучше использовать DataReader с установленным SequentialAccess, а затем вызывать GetBytes для считывателя для возвращаемого поля. Вызывая это, вы извлекаете только те байты, которые вам нужны, и можете обрабатывать данные кусками.
Это важно, потому что у вас наверняка будут проблемы с выделением массива байтов размером 2 МБ. Вообще говоря, начинать выделять большие непрерывные блоки памяти (а это и есть массивы) - плохая идея, и она снижает производительность. Где возможно, обрабатывайте данные небольшими порциями.