Estamos trabajando en una aplicación web, aún no accesible para los usuarios. Mi jefe notó que los registros recién creados obtienen una identificación de más de 10 000, a pesar de que solo tenemos menos de 100 registros en la tabla. Ella asumió que la interfaz web por alguna razón crea más de 100 veces más registros temporales que los reales (y los elimina) y que esto puede llevarnos a quedar fuera de alcance dentro de unos pocos meses de su lanzamiento.
No creo que tenga razón sobre la causa de la inflación de la identificación (el colega que puede responder esto está de vacaciones, por lo que no lo sabemos con certeza), pero supongamos que sí. Ella dijo que odiaría usar una columna bigint, y que le gustaría que dejáramos de aumentar automáticamente la columna de ID y escribir el código del lado del servidor que elige el primer entero "no utilizado" y lo usa como ID.
Soy un estudiante graduado de ciencias de la computación con poca experiencia práctica, desempeñando un rol de desarrollador junior. Tiene años de experiencia en la gestión de todas las bases de datos de nuestra organización y en el diseño de la mayoría de ellas. Yo creo que ella es incorrecta en este caso, que un documento de identidad bigint hay nada que temer, y que imitan la funcionalidad DBMS olores de un anti patrón. Pero todavía no confío en mi juicio.
¿Cuáles son los argumentos a favor y en contra de cada posición? ¿Qué cosas malas pueden pasar si usamos un bigint, y cuáles son los peligros de reinventar la funcionalidad de autoincremento de la rueda ? ¿Hay una tercera solución que sea mejor que cualquiera? ¿Cuáles podrían ser sus razones para querer evitar una inflación de los valores nominales de identificación? También estoy interesado en conocer razones pragmáticas: ¿tal vez las ID de bigint funcionan en teoría, pero causan dolores de cabeza en la práctica?
No se espera que la aplicación maneje grandes cantidades de datos. Dudo que alcance los 10 000 registros reales en los próximos años.
Si hace alguna diferencia, estamos usando el servidor Microsoft SQL. La aplicación está escrita en C # y usa Linq to SQL.
Actualizar
Gracias, encontré interesantes las respuestas y comentarios existentes. Pero me temo que no entendiste mi pregunta, por lo que contienen lo que quería saber.
No estoy realmente preocupado por la verdadera razón de las altas ID. Si no podemos encontrarlo por nuestra cuenta, podría hacer una pregunta diferente. Lo que me interesa es entender el proceso de decisión en este caso. Para esto, suponga que la aplicación escribirá 1000 registros por día y luego eliminará 9999 de ellos . Estoy casi seguro de que este no es el caso, pero esto es lo que mi jefe creía cuando hizo su pedido. Entonces, en estas circunstancias hipotéticas, ¿cuáles serían las ventajas y desventajas de usar bigint o escribir nuestro propio código que asignará ID (de una manera que reutilice las ID de los registros ya eliminados, para garantizar que no haya vacíos)?
En cuanto a la razón real, sospecho fuertemente que esto se debe a que una vez escribimos código para importar datos de otra base de datos, como prueba de concepto de que una migración posterior se puede hacer en cierta medida. Creo que mi colega realmente creó varios miles de registros durante la importación y luego los eliminó. Tengo que confirmar si este fue realmente el caso, pero si es así, ni siquiera hay necesidad de acción.
fuente
Respuestas:
Sin ver el código, es bastante difícil decir de manera concluyente lo que está sucediendo. Aunque, lo más probable es que el
IDENTITY
valor se esté almacenando en la memoria caché, lo que provoca brechas en el valor después de reiniciar SQL Server. Consulte /programming/17587094/identity-column-value-suddenly-jumps-to-1001-in-sql-server para obtener algunas buenas respuestas e información al respecto.Un
INT
campo simple puede contener valores de hasta 2,147,483,647. En realidad, puede iniciar el valor de identidad en -2,147,483,648, dando un total de 32 bits de valores. 4 mil millones de valores distintos. Dudo mucho que te quedes sin valores para usar. Asumiendo que su aplicación está consumiendo 1.000 valores para cada fila añadido real, que había necesidad de ser la creación de cerca de 12.000 filas por día todos los días de quedarse sin identificaciones en 6 meses, suponiendo que inició elIDENTITY
valor a 0, y estaban usando un INT. Si usara un BIGINT, tendría que esperar 21 millones de siglos antes de quedarse sin valores si escribiera 12,000 filas por día, consumiendo 1,000 "valores" por fila.Habiendo dicho todo eso, si quisieras usarlo
BIGINT
como el tipo de datos del campo de identidad, ciertamente no hay nada de malo en eso. Eso le dará, a todos los efectos, un suministro ilimitado de valores para usar. La diferencia de rendimiento entre un INT y un BIGINT es prácticamente inexistente en el hardware moderno de 64 bits, y es altamente preferible sobre, por ejemplo, el usoNEWID()
para generar GUID.Si desea administrar sus propios valores para la columna ID, puede crear una tabla de claves y proporcionar una forma bastante segura de hacerlo utilizando uno de los métodos que se muestran en las respuestas a esta pregunta: Manejo del acceso concurrente a una tabla de claves sin puntos muertos en SQL Server
La otra opción, suponiendo que esté usando SQL Server 2012+, sería usar un
SEQUENCE
objeto para obtener valores de ID para la columna. Sin embargo, necesitaría configurar la secuencia para que no almacene valores. Por ejemplo:En respuesta a la percepción negativa de su jefe de los números "altos", diría ¿qué diferencia hace? Suponiendo que use un
INT
campo, con unIDENTITY
, de hecho podría comenzarIDENTITY
en2147483647
e "incrementar" el valor en-1
. Esto no cambiaría en absoluto el consumo de memoria, el rendimiento o el espacio en disco utilizado, ya que un número de 32 bits es de 4 bytes, sin importar si es0
o no2147483647
.0
en binario es00000000000000000000000000000000
cuando se almacena en unINT
campo con signo de 32 bits .2147483647
es01111111111111111111111111111111
- ambos números ocupan exactamente la misma cantidad de espacio, tanto en la memoria como en el disco, y ambos requieren exactamente la misma cantidad de operaciones de CPU para procesar. Es mucho más importante obtener el código de su aplicación diseñado correctamente que obsesionarse con el número real almacenado en un campo clave.Preguntó sobre los pros y los contras de (a) usar una columna de ID de mayor capacidad, como a
BIGINT
, o (b) implementar su propia solución para evitar lagunas de ID. Para responder a estas preocupaciones:BIGINT
en lugar deINT
como el tipo de datos para la columna en cuestión. El uso de aBIGINT
requiere el doble de la cantidad de almacenamiento, tanto en disco como en memoria para la columna misma. Si la columna es el índice de clave principal para la tabla involucrada, todos y cada uno de los índices no agrupados adjuntos a la tabla también almacenarán elBIGINT
valor, al doble del tamaño de unaINT
, nuevamente en la memoria y en el disco. SQL Server almacena datos en el disco en páginas de 8 KB, donde el número de "filas" por "página" depende del "ancho" de cada fila. Entonces, por ejemplo, si tiene una tabla con 10 columnas, cada unaINT
, podrá almacenar aproximadamente 160 filas por página. Si esas columnas en su lugarBIGINT
columnas, solo podrá almacenar 80 filas por página. Para una tabla con un número muy grande de filas, esto claramente significa que la E / S requerida para leer y escribir la tabla será doble en este ejemplo para cualquier número dado de filas. Por supuesto, este es un ejemplo bastante extremo: si tuviera una fila que constara de una sola columnaINT
oBIGINT
columna y una solaNCHAR(4000)
columna, (simplistamente) obtendría una sola fila por página, ya sea que usara unaINT
o unaBIGINT
. En este escenario, no habría mucha diferencia apreciable.Rodando su propio escenario para evitar vacíos en la columna ID. Debería escribir su código de tal manera que determinar el "próximo" valor de ID a utilizar no entre en conflicto con otras acciones que sucedan en la tabla. Algo a lo largo de las líneas de
SELECT TOP(1) [ID] FROM [schema].[table]
ingenuidad viene a la mente. ¿Qué sucede si hay varios actores que intentan escribir nuevas filas en la tabla simultáneamente? Dos actores podrían obtener fácilmente el mismo valor, resultando en un conflicto de escritura. Para solucionar este problema, se requiere acceso en serie a la tabla, lo que reduce el rendimiento. Se han escrito muchos artículos sobre este problema; Dejaré que el lector realice una búsqueda sobre ese tema.La conclusión aquí es: debe comprender sus requisitos y estimar adecuadamente tanto el número de filas como el ancho de las filas, junto con los requisitos de concurrencia de su aplicación. Como de costumbre, depende de ™.
fuente
bigint
que probablemente se agradecerá para decidir de antemano que en lugar de tener que añadir esto en una mesa con mil millones de filas.La tarea principal es encontrar la causa raíz por la cual el valor actual es tan alto.
La explicación más razonable para las versiones de SQL Server anteriores a SQL2012, suponiendo que esté hablando de una base de datos de prueba, sería que hubo una prueba de carga seguida de una limpieza.
A partir de SQL2012, la razón más probable se debe a varios reinicios del motor SQL (como se explica en el primer enlace que proporcionó Max).
Si la brecha es causada por un escenario de prueba, no hay razón para preocuparse desde mi punto de vista. Pero para estar seguro, verificaría los valores de identidad durante el uso normal de la aplicación, así como antes y después de reiniciar el motor.
Es "gracioso" que MS afirme que ambas alternativas (ya sea el indicador de rastreo 272 o el nuevo objeto SEQUENCE) podrían afectar el rendimiento.
Podría ser la mejor solución para usar BIGINT en lugar de INT solo para estar seguro para cubrir las próximas "mejoras" de MS ...
fuente
Rumtscho, si solo está creando 1000 filas por día, hay poco que decidir: use el tipo de datos INT con un campo Identidad y termine con él. Las matemáticas simples dicen que si le da a su aplicación un ciclo de vida de 30 años (poco probable), podría tener 200,000 filas por día y aún estar dentro del rango de número positivo de un tipo de datos INT.
El uso de BigInt es excesivo en su caso, también puede causar problemas si se accede a su aplicación o sus datos a través de ODBC (como traerlos a Excel o MS Access, etc.), Bigint no se traduce bien en la mayoría de los controladores ODBC a las aplicaciones de escritorio.
En cuanto a los GUID, aparte del espacio de disco adicional y la E / S adicional, existe el gran problema de que, por diseño, no son secuenciales, por lo que si forman parte de un índice ordenado, puede adivinar que cada inserción va a requieren que se recurra al índice. --Jim
fuente
Hay una brecha entre los valores utilizados? ¿O los valores iniciales son 10.000 y a partir de entonces todos suman 1? A veces, si el número se va a dar a los clientes, el número inicial es mayor que cero, digamos 1500 por ejemplo, por lo que el cliente no se da cuenta de que el sistema es "nuevo".
El inconveniente de usar bigint en lugar de smallint es que como bigint usa "más espacio en disco", cuando lee el disco, lee menos bloques de disco para cada disco. Si su espacio de fila es pequeño, esto puede ser un inconveniente, si no es así, no importa mucho. Además, no importa mucho si no está consultando muchos recursos a la vez y si tiene los índices adecuados.
Y como se dijo en otra respuesta, si le preocupa quedarse sin índices, entonces no debe preocuparse, smallint puede manejar a menos que tenga un negocio millonario. Inventar un mecanismo para "recuperar identificadores" es costoso y agrega puntos de falla y complejidad al software.
Saludos
fuente
Si yo fuera tu jefe, estaría más interesado en las razones de los valores de Id inesperadamente altos ... tal como lo veo, para cada uno de los dos escenarios que describiste:
SI las pruebas anteriores han aumentado los valores de identidad, entonces sus otros comentarios sobre el número esperado de registros también me obligarían a sugerir un tipo de clave más pequeño. Francamente, también consideraría si fuera posible restablecer la secuencia y volver a numerar los registros existentes si la prueba no fuera de carácter para el uso previsto actual de la tabla (la mayoría consideraría esta exageración: 'depende').
SI la mayoría de los registros escritos en la tabla se eliminan poco después, me inclinaría a considerar usar dos tablas; una tabla temporal donde los registros no se mantienen a largo plazo, y otra donde solo se mantienen registros que crearemos permanentemente. Una vez más, sus expectativas sobre la cantidad de registros a largo plazo me sugieren el uso de un tipo más pequeño para su columna clave, y unos pocos registros por día difícilmente le causarán un problema de rendimiento para 'mover' un registro de una tabla a otra similar. uno. Sospecho que no es su escenario, pero imagine que un sitio web de compras puede preferir mantener un Basket / BasketItem y cuando se realiza un pedido, los datos se mueven al conjunto Order / OrderItem.
Resumir; en mi opinión, los BIGINT no son necesariamente temibles, pero son francamente innecesarios para muchos escenarios. Si la tabla nunca se agranda, nunca se dará cuenta de que hubo una exageración en su elección de tipo ... pero cuando tiene tablas con millones de filas y muchas columnas FK que son GRANDES cuando podrían haber sido más pequeñas, entonces puede desear que los tipos se seleccionaron de forma más conservadora (tenga en cuenta no solo las columnas de teclas, sino todas las columnas de teclas principales y todas las copias de seguridad que guarda, etc.). El espacio en disco no siempre es barato (considere el disco SAN en ubicaciones administradas, es decir, el espacio en disco se alquila).
En esencia, estoy abogando por una cuidadosa consideración de su selección de tipo de datos siempre en lugar de a veces . No siempre predecirá los patrones de uso correctamente, pero creo que tomará mejores decisiones como regla general y luego supondrá que "más grande es mejor". En general, selecciono el tipo más pequeño que puede contener el rango de valores requerido y razonable y felizmente consideraré INT, SMALLINT e incluso TINYINT si creo que es probable que el valor se ajuste a ese tipo en el futuro previsible. Sin embargo, es poco probable que los tipos más pequeños se usen con columnas IDENTITY, pero pueden usarse felizmente con tablas de búsqueda donde los valores clave se configuran manualmente.
Finalmente, las tecnologías que las personas usan pueden influir considerablemente en sus expectativas y respuestas. Es más probable que algunas herramientas causen lagunas en los rangos, por ejemplo, al reservar previamente rangos de identidades por proceso. En contraste, @DocSalvager sugiere una secuencia auditable exhaustiva que parece reflejar el punto de vista de su jefe; Personalmente, nunca he requerido ese nivel de autoridad, aunque la regla general de que las identidades son secuenciales y generalmente sin brechas a menudo me ha sido increíblemente útil en situaciones de apoyo y análisis de problemas.
fuente
Utilizando
bigint
como identidad y viviendo con las brechas:int
que todavía le daría datos de aproximadamente 2 millones de días; se deberán leer y escribir más páginas; los índices pueden hacerse más profundos. (Sin embargo, en estos volúmenes esto no es una preocupación importante).Ruede el suyo:
fuente
Si realmente le preocupa alcanzar el umbral superior de INT para sus PK, considere usar GUID. Sí, sé que son 16 bytes frente a 4 bytes, pero el disco es barato.
Aquí hay una buena reseña de pros y contras.
fuente
RDBMS Claves primarias (columna generalmente llamada 'ID')
No se pueden evitar espacios en columnas (campos) de autoincremento RDBMS. Están destinados principalmente a crear PK únicas. Para el rendimiento, los principales productos los asignan en lotes, por lo que los mecanismos de recuperación automática para varios fallos de funcionamiento normales pueden provocar que los números no se usen. Esto es normal.
Secuencias ininterrumpidas
Cuando necesita un número de secuencia ininterrumpida, como suele ser esperado por los usuarios, debe ser una columna separada que se asigne mediante programación y no debe ser la PK. Por lo tanto, esos 1000 registros pueden tener el mismo número en esa columna.
¿Por qué los usuarios quieren secuencias ininterrumpidas?
Los números de secuencia faltantes son el signo más básico de error descubierto en cualquier tipo de auditoría. Este principio de "Contabilidad-101" es omnipresente. Sin embargo, lo que funciona para un pequeño número de registros mantenidos a mano, tiene un grave problema cuando se aplica a un gran número de registros en bases de datos ...
La reutilización de valores clave para registros no relacionados invalida la base de datos El
uso del "primer entero no utilizado" introduce la probabilidad de que en algún momento en el futuro, un número sea reutilizado para registros no relacionados con el original. Eso hace que la base de datos no sea confiable como una representación precisa de los hechos. Esta es la razón principal por la que los mecanismos de autoincremento están diseñados a propósito para nunca reutilizar un valor.
fuente