Optimización del Almacenamiento de Direcciones IP en Bases de Datos
El problema con VARCHAR para IPs
Por inercia, muchos desarrolladores almacenan direcciones IP como cadenas VARCHAR(15) en sus bases de datos. Si bien esto funciona, tiene varias desventajas:
- Mayor consumo de espacio (hasta 15 bytes por dirección)
- Búsquedas menos eficientes
- Validación adicional requerida
- Problemas de ordenamiento incorrecto
💡 ¿Sabías que?
Una dirección IPv4 realmente es un número de 32 bits, que puede ser almacenado en solo 4 bytes usando INT UNSIGNED, en lugar de los 15 bytes que requiere VARCHAR.
Solución: INT UNSIGNED y funciones MySQL
MySQL ofrece funciones nativas para convertir entre la representación de cadena y numérica de direcciones IP:
Conversión de IP a entero
-- Convertir una dirección IP a formato numérico
SELECT INET_ATON('192.168.0.10') AS ip_numero;
-- Resultado: 3232235530Conversión de entero a IP
-- Convertir un número de vuelta a dirección IP
SELECT INET_NTOA(3232235530) AS ip_direccion;
-- Resultado: '192.168.0.10'Implementación en una tabla
Creación de una tabla optimizada para almacenar direcciones IP:
CREATE TABLE acceso_usuarios (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
usuario_id INT UNSIGNED NOT NULL,
-- En lugar de: ip_address VARCHAR(15)
ip_address INT UNSIGNED NOT NULL,
fecha_acceso TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_ip (ip_address)
);Inserción de datos
-- Insertar una nueva dirección IP convertida a entero
INSERT INTO acceso_usuarios (usuario_id, ip_address)
VALUES (1025, INET_ATON('192.168.0.10'));Consulta de datos
-- Consultar la dirección IP en formato legible
SELECT id, usuario_id, INET_NTOA(ip_address) AS ip, fecha_acceso
FROM acceso_usuarios;Comparación: VARCHAR vs INT UNSIGNED
❌VARCHAR(15)- 15 bytes por dirección
- Búsquedas más lentas
- Ordenamiento lexicográfico
- Validación manual necesaria
- Problemas con espacios en blanco
✅INT UNSIGNED- Solo 4 bytes por dirección
- Búsquedas más rápidas
- Ordenamiento numérico correcto
- Validación automática con INET_ATON
- Formato consistente
Ejemplo de ordenamiento incorrecto con VARCHAR
Al ordenar direcciones IP como cadenas, el resultado no es el esperado:
IP como VARCHAR Orden lexicográfico Orden numérico correcto 192.168.0.1 1º 3º 192.168.0.2 2º 4º 192.168.0.10 3º 1º 192.168.0.20 4º 2º
Consideraciones para IPv6
Para direcciones IPv6, que son de 128 bits, MySQL ofrece funciones similares:
-- Para IPv6 (MySQL 5.6 y superior)
SELECT INET6_ATON('2001:0db8:85a3:0000:0000:8a2e:0370:7334');
SELECT INET6_NTOA(direccion_ipv6) FROM tabla;
Para almacenar IPv6, se recomienda usar BINARY(16) en lugar de INT UNSIGNED:
CREATE TABLE conexiones (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-- Para IPv4 e IPv6
ip_address VARBINARY(16) NOT NULL,
es_ipv6 BOOLEAN DEFAULT FALSE
);
Mejores Prácticas
En aplicaciones
En tu código de aplicación, puedes realizar las conversiones:
Ejemplo en PHP:
// Convertir IP a entero para almacenar
$ip_int = ip2long('192.168.0.10');
// Convertir de vuelta para mostrar
$ip_str = long2ip($ip_int);
Ejemplo en Python:
# Convertir IP a entero
import socket, struct
ip_int = struct.unpack("!L", socket.inet_aton(ip_str))[0]
# Convertir de vuelta
ip_str = socket.inet_ntoa(struct.pack("!L", ip_int))
En consultas
Para búsquedas por rango de IPs:
-- Encontrar todas las IPs en el rango 192.168.0.0 - 192.168.0.255
SELECT * FROM acceso_usuarios
WHERE ip_address BETWEEN
INET_ATON('192.168.0.0') AND INET_ATON('192.168.0
Gracias por el aporte.
ResponderBorrarSirve para almacenar de datos tipo LOG y no ocupe mucho espacio en la base de datos
ResponderBorrar