Помните, что IP-адреса - это не текстовый адрес, а числовой идентификатор. У меня похожая ситуация (мы выполняем поиск по гео-ip), и если вы храните все свои IP-адреса в виде целых чисел (например, мой IP-адрес 192.115.22.33, поэтому он хранится как 3228767777), то вы можете искать IP-адреса легко с помощью операторов правого сдвига.
Недостатком всех этих типов поиска является то, что вы не можете извлечь выгоду из индексов, и вы должны выполнять полное сканирование таблицы всякий раз, когда вы выполняете поиск. Приведенную выше схему можно улучшить, сохранив как сетевой IP-адрес сети CIDR (начало диапазона), так и широковещательный адрес (конец диапазона), поэтому, например, для хранения 192.168.1.0/24 можно сохранить два столбцы:
network broadcast
3232235776, 3232236031
И тогда вы можете соответствовать этому, вы просто делаете
SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast
Это позволит вам хранить сети CIDR в базе данных и быстро и эффективно сопоставлять их с IP-адресами, используя быстрые числовые индексы.
Заметка из обсуждения ниже :
MySQL 5.0 включает в себя оптимизацию ранжированных запросов, которая называется " index merge intersect ", что позволяет ускорить такие запросы (и избежать полного сканирования таблицы), если:
- Существует многостолбцовый индекс, который точно соответствует столбцам в запросе по порядку. Итак, для приведенного выше примера запроса индекс должен быть
(network, broadcast)
.
- Все данные можно извлечь из индекса. Это верно для
COUNT(*)
, но не верно для SELECT * ... LIMIT 1
.
MySQL 5.6 включает в себя оптимизацию под названием MRR, которая также ускорит поиск всей строки, но это выходит за рамки этого ответа.