2010-09-17 12 views
11

, que es la mejor clave principal para almacenar la dirección del sitio web y las URL de las páginas?¿Cuál es la mejor clave principal para almacenar las URL

Para evitar el uso de identificación autoincremental (que no está realmente vinculada a los datos), diseñé el esquema con el uso de una firma SHA1 de la URL como clave principal.

Este enfoque es útil de muchas maneras: por ejemplo, no necesito leer el last_id de la base de datos para poder preparar todas las actualizaciones de la tabla calculando la clave y hacer la actualización real en una sola transacción. Sin restricción de restricción.

De todos modos, leí dos libros que me dicen que estoy equivocado. En "MySQL de alto rendimiento" se dice que la clave aleatoria no es buena para el optimizador de DB. Además, en los libros de Joe Celko dice que la clave principal debe ser parte de los datos.

La pregunta es: las claves naturales para las URL son ... Las propias URL. El hecho es que si para un sitio es corto (www.something.com), no hay un límite impuesto para am URL (ver http://www.boutell.com/newfaq/misc/urllength.html).

Considere que tengo que almacenar (y trabajar con) algunos millones de ellos.

¿Cuál es la mejor clave, entonces? Autoincremental ids, URLs, hashes de URLs?

+1

Creo que va a depender mucho de qué más está haciendo con estas URL, patrones de acceso, etc. El uso de SHA1 debería estar a salvo de colisiones, donde una función hash más corta (por ejemplo, CRC32) obviamente sería inapropiada, pero las colisiones aún pueden ser posibles, solo tendrás mala suerte. –

Respuesta

15

Querrá una clave primaria numérica autoincrement. Para los momentos en que necesite pasar los identificadores o unirse a otras tablas (por ejemplo, atributos opcionales para una URL), querrá algo pequeño y numérico.

En cuanto a qué otras columnas e índices desea, depende, como siempre, de cómo va a usarlos.

Una columna que almacena un hash de cada URL es una excelente idea para casi cualquier aplicación que utilice un número significativo de URL. Hace SELECCIONAR una URL por su texto completo tan rápido como se va a obtener. Una segunda ventaja es que si hace que la columna sea ÚNICA, no tiene que preocuparse por hacer que la columna que almacena la URL real sea única, y puede usar REEMPLAZAR ENTRAR e INSERTAR IGNORAR como operaciones simples y rápidas de escritura atómica.

Me gustaría añadir que el uso de la función integrada MD5() de MySQL está muy bien para este propósito. Su única desventaja es que un atacante dedicado puede forzar colisiones, lo cual estoy seguro de que no te importa. El uso de la función incorporada hace que, por ejemplo, algunos tipos de uniones sean mucho más fáciles. Puede ser un poco más lento pasar una URL completa a través del cable ("SELECCIONAR url FROM urls WHERE hash = MD5 ('verylongurl')" en lugar de "WHERE hash = '32charhexstring'"), pero tendrá la opción para hacer eso si quieres A menos que se te ocurra un escenario concreto en el que MD5() te defraudará, no dudes en utilizarlo.

La pregunta difícil es si debe buscar URLs, y de qué manera, y no de texto completo: por ejemplo, ¿desea buscar todas las URL que comiencen con "/ foo" en cualquier "barra". com "host? Mientras "LIKE '% bar.com%/foo%'" funcionará en las pruebas, fallará miserablemente a escala. Si sus necesidades incluyen cosas como esas, puede encontrar maneras creativas de generar índices no ÚNICOS dirigidos al tipo de datos que necesita ... tal vez una columna domain_name, para empezar. Tendrás que completar esas columnas desde tu aplicación, casi con certeza (los desencadenantes y los procedimientos almacenados son mucho más problemáticos de lo que valen aquí, especialmente si te preocupa el rendimiento, no te molestes).

La buena noticia es que las bases de datos relacionales son muy flexibles para ese tipo de cosas. Siempre puede agregar nuevas columnas y completarlas más tarde. Sugeriría para principiantes: int clave aut .incremento unsigned, carácter hash único (32) y (suponiendo que 64 caracteres de caracteres suficientes) url de texto.

+0

+1 - hay serias implicaciones de rendimiento al tener claves primarias más amplias, bien documentadas por el equipo de SQL y generalmente ignoradas por la mayoría de los desarrolladores. – TomTom

+0

¿Por qué almacenar hash como hexadecimal en lugar de forma decimal? –

1

Depende de cómo usa la tabla. Si selecciona principalmente con WHERE url='<url>', está bien tener una tabla de una columna. Si puede usar una identificación de autoincrement para identificar una URL en todos los lugares de su aplicación, use la autoincrementación

2

Probablemente está hablando de una URL completa, no solo de un nombre de host, incluidos los parámetros CGI y otras cosas.

SHA-1 hash de las URL hace que todas las claves sean largas, y hace que la resolución de problemas sea bastante oscura. Tuve que usar índices en hashes una vez para ocultar algunos datos confidenciales, manteniendo la capacidad de unir dos tablas, y el rendimiento fue pobre.

Hay dos enfoques posibles. Una es la ingenua y obvia; en realidad funcionará bien en mySQL. Tiene ventajas como la simplicidad y la capacidad de usar URL LIKE 'whatever%' para buscar de manera eficiente.

Pero si usted tiene un montón de direcciones URL se concentran en unos pocos dominios ... por ejemplo ....

http://stackoverflow.com/questions/3735390/best-primary-key-for-storing-urls 
http://stackoverflow.com/questions/3735391/how-to-add-a-c-compiler-flag-to-extconf-rb 

etc, usted está buscando en los índices que varían sólo en los últimos caracteres. En este caso, puede considerar almacenar e indexar las URL con el orden de caracteres invertido. Esto puede conducir a un índice de acceso más eficiente.

(El producto de servidor de tabla de Oracle pasa ha construido en un modo de hacer esto con un índice de llamada revertida.)

Si yo fuera usted quisiera evitar una clave de incremento automático a menos que usted tiene que unirse más de dos tablas ON TABLE_A.URL = TABLE_B.URL o alguna otra condición de unión con ese tipo de medición.

+1

Una forma de mejorar el rendimiento de las uniones en hashes es agregar una segunda columna indexada con una versión más "concentrada" de los datos hash. Un BIGINT con los primeros 64 bits de un MD5 se puede indexar de manera más eficiente que un CHAR (32). Las colisiones serán un billón de veces más comunes, es decir, extremadamente raras. Su WHERE puede unirse en ambas columnas ("WHERE t1.inthash = t2.inthash AND t1.charhash = t2.charhash") y en el caso extremadamente raro de una colisión BIGINT, el hash completo garantizará que siga obteniendo la respuesta correcta. –

Cuestiones relacionadas