Все зависит от формата хранения/представления этих данных. Должен быть свой кастомный формат, компактный (чтобы сократить доступ к памяти) и удобный исключительно для быстрого сканирования (прохода по всем записям), и ни для чего другого. Я бы написал это под Cython или Numba с компактным представлением данных в Numpy. При таком большом количестве мелких записей и, в общем то, тривиальном алгоритме их обработки основным bottleneck в плане производительности становится не CPU, а доступ к RAM, поэтому от "хитрости" самого алгоритма подсчета (какие тут могут быть хитрости?) тут мало что зависит, зато компактность структуры данных (даже за счет не очень удобного доступа к ней) будет играть решающую роль.