Can't you use count before iterating?
From the query builder which will run on the database as a separate query. If the where condition is on indexed fields it should run fast enough even for massive amounts of rows.
$query = DB::connection('mysql_unbuffered')
->table($table)
->select($columns)
->where('account_id', $accountId)
->groupBy($groupBy)
->orderBy($orderBy);
$count = $query->count(); // run count in DB
$threshold = intval(ceil($count / 10)); // each 10%
foreach($query->cursor() as $key => $item) {
$percentage = $key * 100.0 / $count;
if ($key % $threshold === 0) {
// send notification
}
// process row
}