Como ahorro espacio en la base de datos?

Iniciado por Skeletron, 10 Febrero 2010, 23:36 PM

0 Miembros y 3 Visitantes están viendo este tema.

Skeletron

Hola gente... Les comento que tengo una base de datos donde cada registro, son links.

Hoy antes de activar el INDEXADOR de una web mia, pense en como hacer para ahorrar datos..

Tambien me dijeron hace un tiempo, en eliminar el http:// de cada link, para ahorrar espacio, como así tambien reemplazar el .com por un *, y el .org por un ] y el www. por un [
O sea, reemplanzar cadenas comunes por simbolos, para ahorrar espacio

Las preguntas son:
Tienen alguna idea mejor, o algo mas para hacer para ahorrar espacio? (no sirve cualquier sistema HASH)
Que simbolos no se utilizan en links? (para poder utilizarlos como reemplazos)


Espero respuestas tios/as!

Encontre una respuesta muy grosa:
http://www.nuevastecnologias.com.ar/2010/04/como-ahorrar-espacio-en-una-base-de.html

^Tifa^

No hay porque reducir palabras para ello... tienes registros en una tabla que son puras direcciones URLs pero sabes que usarlas de indice es un crimen para el optimizador interno del motor y esto sin contar la lentitud que provocaria  :P  tengo un amigo programador en PHP que tenia un problema similar. El me decia como puedo crear un campo indice (ID) para cada Url si yo no voy a recordarme que ID le corresponde al registro 200 (por ejemplo). Entonces le di una solucion que espero tambien te pueda servir he de igual forma a otros webmasters porque se que esto es un dilema que ha de ocurrir bastante.

Tu me confirmas que tienes una tabla que solo guarda direcciones URLs en los campos. Asumo que es algo mas o menos asi:

Código (sql) [Seleccionar]


mysql> select * from ejemplo;
+-------------------------------------+
| direcciones                         |
+-------------------------------------+
| http://www.google.com               |
| http://www.yahoo.com/index.html     |
| http://www.amazon.com/index.php     |
| http://foro.elhacker.net/index.php  |
| http://www.unix.com/index.html?id=5 |
+-------------------------------------+
5 rows in set (0.00 sec)



Y tienes como index dicho campo (en mi caso direcciones) que es un VARCHAR de longitud variable le asigne 70 de longitud pero sabemos que es dinamica la reserva aca  :xD  eso es cruel y pesimo de usarlo como indice. Reducir o quitarle los 'http'  no es solucion. Asignarle un ID tampoco porque no vas a saberte el ID correspondiente a cada URL vamos (sobretodo si hablamos de cientos sino miles de URL como registros). Asi que tienes una opcion especial, asigna un campo extra de tipo DECIMAL el cual usaras como indice:

Código (sql) [Seleccionar]


mysql> alter table ejemplo add codigo decimal(10,0);
Query OK, 5 rows affected (0.07 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> create index indice on ejemplo(codigo);
Query OK, 5 rows affected (0.07 sec)
Records: 5  Duplicates: 0  Warnings: 0



En esta parte la tarea te costara, pero valdra la pena, ya que ahora insertaras los datos de esta manera a la DB:

Código (sql) [Seleccionar]


mysql> insert into ejemplo values('http://www.google.com',crc32('http://www.google.com')), ('http://www.yahoo.com',crc32('http://www.yahoo.com')), ('httpd://foro.elhacker.net',crc32('http://foro.elhacker.net'));
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from ejemplo;
+---------------------------+------------+
| direcciones               | codigo     |
+---------------------------+------------+
| http://www.google.com     | 1587574693 |
| http://www.yahoo.com      |  416577886 |
| httpd://foro.elhacker.net |  794697805 |
+---------------------------+------------+
3 rows in set (0.00 sec)


Ahora diras sino puedo recordarme de un ID sencillo de 1 o 2 cifras como voy a recordar esos numeros tan largos en el campo codigo  :-\  simple la busquedad de la data la haras asi:

Código (sql) [Seleccionar]


mysql> select * from ejemplo;
+---------------------------+------------+
| direcciones               | codigo     |
+---------------------------+------------+
| http://www.google.com     | 1587574693 |
| http://www.yahoo.com      |  416577886 |
| httpd://foro.elhacker.net |  794697805 |
+---------------------------+------------+
3 rows in set (0.00 sec)

mysql> select * from ejemplo where codigo = crc32('http://www.google.com');
+-----------------------+------------+
| direcciones           | codigo     |
+-----------------------+------------+
| http://www.google.com | 1587574693 |
+-----------------------+------------+
1 row in set (0.02 sec)

mysql> select * from ejemplo where codigo = crc32('http://www.yahoo.com');
+----------------------+-----------+
| direcciones          | codigo    |
+----------------------+-----------+
| http://www.yahoo.com | 416577886 |
+----------------------+-----------+
1 row in set (0.00 sec)





Vas captando algo muchacho? Ahora analizemos que dice el optimizador de MySQL sobre esta consulta:

Código (sql) [Seleccionar]


mysql> explain select * from ejemplo where codigo = crc32('http://www.yahoo.com');
+----+-------------+---------+------+---------------+--------+---------+-------+------+-------------+
| id | select_type | table   | type | possible_keys | key    | key_len | ref   | rows | Extra       |
+----+-------------+---------+------+---------------+--------+---------+-------+------+-------------+
|  1 | SIMPLE      | ejemplo | ref  | indice        | indice | 6       | const |    1 | Using where |
+----+-------------+---------+------+---------------+--------+---------+-------+------+-------------+
1 row in set (0.00 sec)



rows = 1
reference = const

;D  super....

Skeletron

#2
O sea que tendria que reemplazar la clave "PRIMARI" del campo "link", y ponercelo a ese codigo que identificará al link?
Y que pasa con las coliciones? Ya que es muy probale que en cantidad de links, llegue aproximadamente a los 2.000.000.000 de registros.
Lo que tu me dices, ahorra tiempo de calculo y espacio por manejar mejor los indices... Pero, yo tengo problemas con el espacio en disco.

Que dices de convinar tu tecnica mas el reemplazo de las siguientes palabras:
       '¢ = www.
       '£ = .com
       '¤ = .org
       '¥ = .net
       '§ = .html
       '± = .htm
       '© = .php
       '® = index
       'µ = .png
       '¼ = .jpg
       '½ = .gif
       '¾ = .png
       'Æ = .jpeg
Entonces generaría ese codigo numerico para un link que esta tambien reducido en longitud por haber reemplazado esos textos(parte derecha), por esos simbolos (parte izquierda)


Porque, mi problema principal, es el espacio, y es verdad lo que tu dices, ya que mas del 50% del espacio, lo gasto en indices.

Imagina el link:
http://www.wikipedia.org/imagenes/simbolodeleuro.jpg >>> 53 bytes
En la base de datos, puede quedan:
¢.wikipedia¤/imagenes/simbolodeleuro¼ >>> 38 bytes
Esto tambien haría que el numero identificador sea mas pequeño aun, y MENOS ESPACIO en disco utilizado

Mira por ejemplo mi querida TIFA:
en 1 minuto, el indexador, tomando como RAIZ a wikipedia.org, encontro 3200 imagenes, de las cuales, 3020 comenzaban con:
http://upload.wikimedia.org/wikipedia/....
Reemplanzar el "http://upload.wikimedia.org/wikipedia/" (ya que, como todos sabemos, es una web que dará un gran porcentaje de las imagenes) por un simbolo, por ejemplo: *, en vez que ocupar 39bytes en ese tramo de link, ocupare solo 2 bites.

Skeletron

Aunque, ahora que veo bien, probando el indexador, y dando como link para que comience a buscar, a WIKIPEDIA: Mira el 1º link que me encontro:
http://as.wikipedia.org/wiki/প্ৰথম_পৃষ্ঠা

Como verás, ahí ya me ocupó la mayoria de los simbolos que pensaba utilizar como reemplazo.
Habria una solucion para ésto? Utilizar otro "lenguaje" para la base de datos, para poder utilizar los simbolos que te mostre arriba, solo para reemplazar esas palabras que te dije.


Porque, te repito: mi principal problema, es ESPACIO EN DISCO

jdc

El problema con los símbolos es que se guardan con su valor ascii

Skeletron

Cita de: ‭ en 11 Febrero 2010, 20:39 PM
El problema con los símbolos es que se guardan con su valor ascii

Esas webs, son coreanas o que se yo (las que dan esos simbolos en los links), lo que podria hacer, es:
Antes de ingresar el link (hay 2 bases de datos, una de LINKS y otras de LINKS DE IMAGENES) a la base de datos, puedo chequear si contiene algun simbolo de los que utilizo, y en caso de ser así, NO LO AGREGO al link, y listo..

^Tifa^

Ten en cuenta que tus datos de las URL no son constantes, por ende definir caracteres de algo para sustituir algunas palabras, no te funcionaria del todo, ya que esto podria provocar que se trunquen data de URL, asi como que 2 URL sean similares  :-\  si tus tablas estan guardadas en motor Myisam, puedes optar por usar la funcionalidad myisampack. Para comprimir tus tablas y asi reducir considerablemente el tamano, por ejemplo checa esta tabla que tengo:

Código (sql) [Seleccionar]


mysql> select * from ejemplo;
+------------+----------------------------------+
| indice     | direccion                        |
+------------+----------------------------------+
| 1587574693 | http://www.google.com            |
|  416577886 | http://www.yahoo.com             |
|  721517199 | http://www.msn.com               |
| 3177037030 | http://www.gogo.com              |
| 1722868955 | http://www.coco.com/imagenes.png |
|  650421202 | www.cucu.com                     |
| 1509117005 | www.foro.org                     |
+------------+----------------------------------+
7 rows in set (0.00 sec)




Y son poquitos datos, pero checa cuanto me ocupa en disco duro el archivo data y indice.

Citarbash-3.1# du -sh *
4.0K    backup1.sql
4.0K    db.opt
94K     ejemplo.MYD
4.0K    ejemplo.MYI
12K     ejemplo.frm

94KB la data  :-\  un poco extenso para 7 miserables registros no... asi que uso la utilidad myisampack y comprimo:

bash-3.1# myisampack ejemplo.*

Ahora checa como redujo:

Citarbash-3.1# du -sh *
4.0K    backup1.sql
4.0K    db.opt
4.0K    ejemplo.MYD
4.0K    ejemplo.MYI
12K     ejemplo.frm

de 94KB a 4.0KB y la data sigue intacta dentro de las tablas.

Ahora existe un incoveniente con myisampack (ya que no todo es religiosamente maravilloso) al comprimir la data, la tabla en cuestion solo tiene permiso de Lectura, por lo que te permite INSERTAR y SELECCIONAR datos, pero no te permite eliminar registros ni actualizar registros  ;)

Otra manera opcional que podrias considerar es utilizar un procedimiento almacenado, para al menos la data que si estas seguro que es constante (como los www y los http) pos hacerlos asi:

Esta es mi tabla por ejemplo:

Código (sql) [Seleccionar]

mysql> select * from ejemplo;
+------------+-----------+   
| indice     | direccion |   
+------------+-----------+   
|  526628817 | google    |   
| 3748556277 | yahoo     |   
| 1257958042 | msn       |   
+------------+-----------+   
3 rows in set (0.00 sec)     



Y hago un procedimiento:

Código (sql) [Seleccionar]


mysql> create procedure copia(palabra char(20)) begin select concat('http://www.', direccion, '.com') from ejemplo where direccion = palabra; end;/
Query OK, 0 rows affected (0.00 sec)                                                                                                               

mysql> delimiter ;
mysql> call copia('google');
+------------------------------------------+
| concat('http://www.', direccion, '.com') |
+------------------------------------------+
| http://www.google.com                    |
+------------------------------------------+
1 row in set (0.01 sec)                     


Skeletron

#7
Mira..
El indexador esta en vb.net, por lo que, al descargar una web(su codigo fuente queda guardado en una variable STRING), o una imagen (queda guardad en un MapaBit), SI O SI tiene que comenzar con http:// el link, por pero como sé que todos comeinzan con http://, lo obviaré y al agregar los items al array para que luego sean procesados, ahí le agregaré el http://, pero no para almacenarlos en la base de datos.

Ahora, hay un problema gigante con dar por obvio el .com, ya que puede ser .com, .com.ar, y demas.. Por eso la idea de reemplazar por simbolos.

Haré eso mi querida TIFA.. reemplazaré por simbolos algunas cadenas de los links, y generaré ese codigo numerico para identificar el link ya con los reemplazos.


Mi pregunta es:
Esos numeros que identificarán al link, que serán el indice PRIMARIO, no terminaran ocupando mas espacio que si tuviese como indice PRIMARIO al link?
Que me dices de las Coliciones con ese numero que identifica? Hay probabilidades de que haya 2 numeros iguales para 2 links diferentes?


Me puse a haces unas pruebas, ahora te digo como va todo

^Tifa^

CitarAhora, hay un problema gigante con dar por obvio el .com, ya que puede ser .com, .com.ar, y demas.. Por eso la idea de reemplazar por simbolos.

Exactamente, como este punto se desconoce (de igual manera si una URL tiene o no www o solo usa http) entonces como tus datos No son constantes... no puedes dar por hecho reemplazar cosas por simbolos. En esa parte ya se ha aclarado que lo unico mas probable que podrias sustituir son los www y los http. Como te decia puedes comprimir las tablas pero deberas conllevar el inconveniente que te expuse (no eliminar no actualizar).

CitarMi pregunta es:
Esos numeros que identificarán al link, que serán el indice PRIMARIO, no terminaran ocupando mas espacio que si tuviese como indice PRIMARIO al link?

Depende, el indice primario que usaras como link cuanto tiene de longitud y que informacion guarda??? porque por ejemplo, si ese indice primario guardase cosas como :

google
msn
yahoo

Perfecto.. no es necesario dar uso a un campo numerico y procura declarar el campo como CHAR en vez de VARCHAR, pero si ese link ocupara cosas como:

google.com/index.html/imagen?
yahoo.com/?pagina.php/imagenes.png

En ese caso No conviene usar indice primario algo asi... una porque el campo en cuestion seria de tipo VARCHAR y VARCHAR es un tipo de dato dinamico no constante, con dinamico implica que aunque tu le des una longitud por ejemplo de 50 bytes si tu informacion ocupa 20 bytes pos nada de esos 50 el ocupa 20 y lo otro lo trunca... y es favorable que para indices se utilizen datos constantes no variables ya que pueden corromperse bajo alguna condicion que no detallare aca porque seria extensa. Por ende si sabes que los links tendran datos de tamano distintos opta por declarar otro campo numerico como te decia.

CitarQue me dices de las Coliciones con ese numero que identifica? Hay probabilidades de que haya 2 numeros iguales para 2 links diferentes?

No, no habran colisiones con ese numero generado por la funcion crc32 que es una funcion matematica, recuerda que dicho campo sera un indice PRIMARIO o UNICO por ende, jamas generara 2 datos iguales, mas bien unicos. (Eres libre de hacer una prueba) los datos son unicos bajo las condiciones que daras, la ventaja es que el campo al ser numerico y como tu sabes que bajo el sistema operativo solicitar informacion numerica es mucho mas rapido que obtener informacion en caracter y luego convertirlo a numerico para entonces interpretar lo que significa, con el campo siendo numerico te evitas ese pekeno pasito extra  ;)


Skeletron

Mira, estoy haciendo las pruebas:
Mira las siguientes imagenes:
la 1º imagen, es la tabla así nomas, sin modificar ni reemplazar nada por nada... la "VIRGEN"
la 2º imagen, es la tabla luego de haber reemplazado las siguientes cadenas:
'ð = upload.wikimedia.org/wikipedia/
        '¢ = www.
        '£ = .com
        '¤ = .org
        '¥ = .net
        '§ = .html
        '± = .htm
        '© = .php
        'µ = .png
        '¼ = .jpg
        '½ = .gif
        'Æ = .jpeg
        '® = index
        'æ = wikipedia


Y tifa, no hay manera de llegar a alcanzar un error o problema al reemplazar esas cadenas por esos simbolos, si se hacen en ese orden que los he puesto.

Primera


Segunda