У меня тут много вопросов возникает.
1) вам нагрузка не нравится, потому что она идёт скачками (в период выполнения тяжёлого запроса) и влияет на выполнение других запросов? Если так, то высасывать данные пачками по 10-100к - нормальный вариант. Можно хоть thread.sleep делать между итерациями. Но нужно придумать, как определять, какие данные уже были выбраны, чтоб эта схема оказалась не *N(батчей) по ресурсоемкости от текущего варианта.
2) эти 14 миллионов записей каждый раз разные? Или постоянно одни и те же данные выбираются, потому что нет инкрементальности? Если так, то добавление инкрементальности в схему/запрос - скорее всего лучшее решение