¿Existe una diferencia de rendimiento medible entre el uso de INT vs. VARCHAR como clave principal en MySQL? Me gustaría usar VARCHAR como clave principal para las listas de referencias (piense en los Estados Unidos, los códigos de país) y un compañero de trabajo no cederá en INT AUTO_INCREMENT como clave principal para todas las tablas.
Mi argumento, como se detalla aquí , es que la diferencia de rendimiento entre INT y VARCHAR es insignificante, ya que cada referencia de clave externa INT requerirá un JOIN para que la referencia tenga sentido, una clave VARCHAR presentará directamente la información.
Entonces, ¿alguien tiene experiencia con este caso de uso en particular y las preocupaciones de rendimiento asociadas con él?
mysql
performance
primary-key
innodb
myisam
Jake McGraw
fuente
fuente
Respuestas:
Usted asegura que puede evitar un cierto número de consultas unidas utilizando lo que se llama una clave natural en lugar de una clave sustituta . Solo usted puede evaluar si el beneficio de esto es significativo en su aplicación.
Es decir, puede medir las consultas en su aplicación que son las más importantes para ser rápido, porque funcionan con grandes volúmenes de datos o se ejecutan con mucha frecuencia. Si estas consultas se benefician de la eliminación de una unión y no sufren al usar una clave primaria varchar, entonces hágalo.
No utilice ninguna estrategia para todas las tablas en su base de datos. Es probable que en algunos casos, una clave natural sea mejor, pero en otros casos una clave sustituta es mejor.
Otras personas señalan que es raro en la práctica que una clave natural nunca cambie o tenga duplicados, por lo que las claves sustitutas generalmente valen la pena.
fuente
No se trata de rendimiento. Se trata de lo que hace una buena clave primaria. Único e inmutable en el tiempo. Puede pensar que una entidad como un código de país nunca cambia con el tiempo y sería un buen candidato para una clave primaria. Pero la experiencia amarga es que rara vez es así.
INT AUTO_INCREMENT cumple la condición "única e inmutable en el tiempo". De ahí la preferencia.
fuente
Estaba un poco molesto por la falta de puntos de referencia para esto en línea, así que realicé una prueba yo mismo.
Sin embargo, tenga en cuenta que no lo hago de forma regular, así que compruebe mi configuración y mis pasos para ver si hay factores que puedan haber influido en los resultados involuntariamente y publique sus inquietudes en los comentarios.
La configuración fue la siguiente:
Las mesas:
Luego, llené 10 millones de filas en cada tabla con un script PHP cuya esencia es así:
Para las
int
tablas, el bit($keys[rand(0, 9)])
se reemplazó con justrand(0, 9)
, y para lasvarchar
tablas, utilicé nombres completos de estados de EE. UU., Sin cortarlos ni extenderlos a 6 caracteres.generate_random_string()
genera una cadena aleatoria de 10 caracteres.Luego corrí en MySQL:
SET SESSION query_cache_type=0;
jan_int
mesa:SELECT count(*) FROM jan_int WHERE myindex = 5;
SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
myindex = 'califo'
parachar
tablas ymyindex = 'california'
paravarchar
tablas.Tiempos de la
BENCHMARK
consulta en cada tabla:En cuanto a los tamaños de tabla e índice, aquí está el resultado de
show table status from janperformancetest;
(con algunas columnas no mostradas):Mi conclusión es que no hay diferencia de rendimiento para este caso de uso en particular.
fuente
INDEX
lugar dePRIMARY KEY
. No recuerdo mi razonamiento: probablemente asumí quePRIMARY KEY
es solo unaINDEX
restricción de singularidad. Sin embargo, al leer la sección sobre cómo se almacenan las cosas en InnoDB en federico-razzoli.com/primary-key-in-innodb , creo que mis resultados aún se aplican a las claves principales y respondo la pregunta sobre la diferencia de rendimiento de la búsqueda de valor. Además, su comentario sugiere analizar el rendimiento de los algoritmos de clasificación , que no se aplican al caso de uso que investigo, que es buscar valores en un conjunto.Depende de la longitud. Si el varchar tendrá 20 caracteres y el int es 4, entonces si usa un int, su índice tendrá CINCO veces más nodos por página de espacio de índice en el disco ... Eso significa que atravesar el índice requerirá una quinta parte de lecturas físicas y / o lógicas.
Entonces, si el rendimiento es un problema, dada la oportunidad, siempre use una clave integral no significativa (llamada sustituto) para sus tablas y para las claves externas que hacen referencia a las filas en estas tablas ...
Al mismo tiempo , para garantizar la coherencia de los datos, cada tabla donde sea importante también debe tener una clave alternativa no numérica significativa (o índice único) para garantizar que no se puedan insertar filas duplicadas (duplicar en función de atributos de tabla significativos).
Para el uso específico del que está hablando (como las búsquedas de estado), realmente no importa porque el tamaño de la tabla es muy pequeño. En general, no hay impacto en el rendimiento de los índices en tablas con menos de unos pocos miles de filas. ..
fuente
Absolutamente no.
He realizado varias ... varias ... comprobaciones de rendimiento entre INT, VARCHAR y CHAR.
La tabla de 10 millones de registros con una CLAVE PRIMARIA (única y agrupada) tenía exactamente la misma velocidad y rendimiento (y costo de subárbol) sin importar cuál de los tres usé.
Dicho esto ... use lo que sea mejor para su aplicación. No te preocupes por el rendimiento.
fuente
Para códigos cortos, probablemente no haya diferencia. Esto es especialmente cierto ya que es probable que la tabla que contiene estos códigos sea muy pequeña (un par de miles de filas como máximo) y no cambie con frecuencia (cuándo es la última vez que agregamos un nuevo Estado de EE. UU.).
Para tablas más grandes con una variación más amplia entre la clave, esto puede ser peligroso. Piense en utilizar la dirección de correo electrónico / nombre de usuario de una tabla de usuario, por ejemplo. Qué sucede cuando tienes unos pocos millones de usuarios y algunos de esos usuarios tienen nombres largos o direcciones de correo electrónico. Ahora, cada vez que necesite unirse a esta tabla con esa tecla, se vuelve mucho más costoso.
fuente
En cuanto a la clave primaria, lo que físicamente hace que una fila sea única debe determinarse como clave principal.
Para una referencia como clave externa, usar un entero de incremento automático como sustituto es una buena idea por dos razones principales.
- Primero, generalmente hay menos gastos generales incurridos en la unión.
- En segundo lugar, si necesita actualizar la tabla que contiene el varchar único, entonces la actualización debe descender en cascada a todas las tablas secundarias y actualizarlas todas, así como los índices, mientras que con el sustituto int, solo tiene que actualizar el tabla maestra y sus índices.
El inconveniente de usar el sustituto es que posiblemente podría permitir cambiar el significado del sustituto:
Todo depende de lo que realmente necesita preocuparse en su estructura y lo que significa más.
fuente
Casos comunes donde
AUTO_INCREMENT
duele un sustituto :Un patrón de esquema común es una asignación de muchos a muchos :
El rendimiento de este patrón es mucho mejor, especialmente cuando se usa InnoDB:
¿Por qué?
id
un índice.Otro caso ( país ):
Con demasiada frecuencia, el novato normaliza country_code en un byte 4 en
INT
lugar de utilizar una cadena 'natural' de 2 bytes, casi inmutable de 2 bytes. Más rápido, más pequeño, menos uniones, más legible.fuente
En HauteLook, cambiamos muchas de nuestras tablas para usar claves naturales. Experimentamos un aumento en el rendimiento en el mundo real. Como mencionas, muchas de nuestras consultas ahora usan menos combinaciones, lo que hace que las consultas sean más efectivas. Incluso usaremos una clave primaria compuesta si tiene sentido. Dicho esto, algunas tablas son más fáciles de trabajar si tienen una clave sustituta.
Además, si permite que las personas escriban interfaces en su base de datos, una clave sustituta puede ser útil. El tercero puede confiar en el hecho de que la clave sustituta cambiará solo en circunstancias muy raras.
fuente
Me enfrenté al mismo dilema. Hice un DW (esquema de constelación) con 3 tablas de hechos, accidentes de tráfico, vehículos en accidentes y víctimas en accidentes. Los datos incluyen todos los accidentes registrados en el Reino Unido desde 1979 hasta 2012, y 60 tablas de dimensiones. En total, unos 20 millones de discos.
Tablas de hechos relaciones:
RDMS: MySQL 5.6
Nativamente, el índice de Accidente es un varchar (números y letras), con 15 dígitos. Intenté no tener claves sustitutas, una vez que los índices de accidentes nunca cambiarían. En una computadora i7 (8 núcleos), el DW se volvió demasiado lento para consultar después de 12 millones de registros de carga, dependiendo de las dimensiones. Después de mucho volver a trabajar y agregar claves sustitutas bigint, obtuve un aumento promedio del rendimiento de velocidad del 20%. Sin embargo, a la baja ganancia de rendimiento, pero prueba válida. Estoy trabajando en MySQL tuning y clustering.
fuente
La pregunta es sobre MySQL, así que digo que hay una diferencia significativa. Si se trataba de Oracle (que almacena números como una cadena, sí, no podía creerlo al principio), entonces no hay mucha diferencia.
El almacenamiento en la tabla no es el problema, pero sí lo es actualizar y hacer referencia al índice. Las consultas que implican buscar un registro en función de su clave principal son frecuentes: desea que ocurran lo más rápido posible porque suceden con tanta frecuencia.
La cosa es que una CPU trata con 4 bytes y enteros de 8 bytes de forma natural, en silicio . Es REALMENTE rápido comparar dos enteros: ocurre en uno o dos ciclos de reloj.
Ahora mire una cadena: está compuesta por muchos caracteres (más de un byte por carácter en estos días). Comparar dos cadenas de precedencia no se puede hacer en uno o dos ciclos. En cambio, los caracteres de las cadenas deben iterarse hasta que se encuentre una diferencia. Estoy seguro de que hay trucos para hacerlo más rápido en algunas bases de datos, pero eso es irrelevante aquí porque la CPU realiza una comparación int de forma natural y muy rápida en silicio.
Mi regla general: cada clave principal debe ser un INT de aumento automático, especialmente en aplicaciones OO que usan un ORM (Hibernate, Datanucleus, lo que sea) donde hay muchas relaciones entre objetos; por lo general, siempre se implementarán como un FK simple y la capacidad para el La base de datos para resolverlos rápidamente es importante para la capacidad de respuesta de su aplicación.
fuente
No estoy seguro de las implicaciones de rendimiento, pero parece que un posible compromiso, al menos durante el desarrollo, sería incluir tanto la clave "sustituta" entera auto-incrementada, como la clave "natural" única e intencionada. Esto le daría la oportunidad de evaluar el rendimiento, así como otros posibles problemas, incluida la posibilidad de cambiar las claves naturales.
fuente
Como de costumbre, no hay respuestas generales. '¡Depende!' y no estoy siendo gracioso Comprendí que la pregunta original era para las claves en tablas pequeñas, como Country (identificación entera o código char / varchar) que es una clave externa para una tabla potencialmente enorme como la tabla de dirección / contacto.
Hay dos escenarios aquí cuando desea recuperar datos de la base de datos. Primero es un tipo de consulta de lista / búsqueda donde desea enumerar todos los contactos con códigos o nombres de estado y país (los identificadores no ayudarán y, por lo tanto, necesitarán una búsqueda). El otro es un escenario de obtención en la clave primaria que muestra un solo registro de contacto donde se debe mostrar el nombre del estado, país.
Para este último, probablemente no importa en qué se base el FK ya que estamos reuniendo tablas para un solo registro o unos pocos registros y en lecturas clave. El primer escenario (búsqueda o lista) puede verse afectado por nuestra elección. Dado que es necesario mostrar el país (al menos un código reconocible y tal vez incluso la búsqueda en sí misma incluye un código de país), potencialmente no tener que unirse a otra tabla a través de una clave sustituta (solo estoy siendo cauteloso aquí porque en realidad no he probado esto, pero parece altamente probable) mejorar el rendimiento; a pesar del hecho de que ciertamente ayuda con la búsqueda.
Como los códigos son de tamaño pequeño, no más de 3 caracteres generalmente para el país y el estado, puede estar bien usar las claves naturales como claves foráneas en este escenario.
El otro escenario donde las claves dependen de valores varchar más largos y quizás de tablas más grandes; la clave sustituta probablemente tiene la ventaja.
fuente
Permítanme decir que sí, definitivamente hay una diferencia, teniendo en cuenta el alcance del rendimiento (definición original):
1- El uso de sustituto int es más rápido en la aplicación porque no necesita usar ToUpper (), ToLower (), ToUpperInvarient () o ToLowerInvarient () en su código o en su consulta y estas 4 funciones tienen diferentes puntos de referencia de rendimiento. Consulte las reglas de rendimiento de Microsoft sobre esto. (rendimiento de la aplicación)
2- El uso de sustituto int garantiza no cambiar la clave con el tiempo. Incluso los códigos de país pueden cambiar, vea Wikipedia cómo los códigos ISO cambiaron con el tiempo. Eso llevaría mucho tiempo cambiar la clave primaria para los subárboles. (rendimiento del mantenimiento de datos)
3- Parece que hay problemas con las soluciones ORM, como NHibernate cuando PK / FK no es int. (rendimiento del desarrollador)
fuente