Способ хранения для 2 млн. записей
Т.е. я так понимаю, оно пополняться не будет? Если нет — то можно сделать свой велосипед на основе flat файлов с фиксированными длинами полей. Будет быстрая выборка обычными seek. По необходимости [s]присыпать солью[/s] разбить на группы по N записей и хранить в отдельных файлах, именованных согласно (id / N), таким образом файловая система будет частично решать вопросы случайного поиска. Если еще дальше развивать идею, можно попробовать еще разбить по папкам (как например хранит кеш squid).

А если же это дело будет регулярно изменяться, то лучше SQL ничего не придумать. 2 Млн записей — не так уж много, тем более что не нужно по ключам выбирать.
К сожалению «простой» массив, целиком загружаемый из файла при каждом запуске скрипта — это и есть самое-самое медленное решение из всех возможных, поскольку очень много времени будет тратиться как раз на разбор содержимого файла, и на создание динамической структуры массива.