Onthoud dat IP's geen tekstueel adres zijn, maar een numerieke ID. Ik heb een vergelijkbare situatie (we doen geo-ip-zoekopdrachten), en als je al je IP-adressen opslaat als gehele getallen (mijn IP-adres is bijvoorbeeld 192.115.22.33, dus het wordt opgeslagen als 3228767777), dan kun je IP-adressen opzoeken gemakkelijk door gebruik te maken van de operators van de rechterploeg.
Het nadeel van al dit soort opzoekingen is dat u geen voordeel kunt halen uit indexen en dat u bij iedere opzoeking een volledige tabelscan moet uitvoeren. Het bovenstaande schema kan worden verbeterd door zowel het netwerk-IP-adres van het CIDR-netwerk (het begin van het bereik) en het uitzendadres (het einde van het bereik) op te slaan, dus om bijvoorbeeld 192.168.1.0/24 op te slaan, kunt u er twee opslaan kolommen:
network broadcast
3232235776, 3232236031
En dan kun je het gewoon evenaren
SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast
Hiermee kunt u CIDR-netwerken in de database opslaan en ze snel en efficiënt vergelijken met IP-adressen door gebruik te maken van snelle numerieke indexen.
Opmerking uit onderstaande discussie :
MySQL 5.0 bevat een ranged query-optimalisatie genaamd "index samenvoegen kruisen " waarmee u dergelijke zoekopdrachten kunt versnellen (en volledige tabelscans kunt vermijden), zolang:
- Er is een index met meerdere kolommen die exact overeenkomt met de kolommen in de zoekopdracht, in volgorde. Dus - voor het bovenstaande queryvoorbeeld zou de index
(network, broadcast)
moeten zijn . - Alle gegevens kunnen uit de index worden gehaald. Dit geldt voor
COUNT(*)
, maar is niet waar voorSELECT * ... LIMIT 1
.
MySQL 5.6 bevat een optimalisatie genaamd MRR die ook het ophalen van volledige rijen zou versnellen, maar dat valt buiten het bestek van dit antwoord.