¿Cuáles son las mejores prácticas para usar un GUID como clave principal, específicamente con respecto al rendimiento?

Tengo una aplicación que usa GUID como clave principal en casi todas las tablas y he leído que hay problemas de rendimiento cuando se usa GUID como clave principal. Honestamente, no he visto ningún problema, pero estoy a punto de comenzar una nueva aplicación y todavía quiero usar los GUID como claves principales, pero estaba pensando en usar una clave primaria compuesta (el GUID y tal vez otro campo .)

Estoy usando un GUID porque son agradables y fáciles de administrar cuando tiene diferentes entornos, como bases de datos de “producción”, “prueba” y “dev”, y también para datos de migración entre bases de datos.

Utilizaré Entity Framework 4.3 y deseo asignar el Guid en el código de la aplicación, antes de insertarlo en la base de datos. (es decir, no quiero permitir que SQL genere el Guid).

¿Cuál es la mejor práctica para crear claves primarias basadas en GUID, a fin de evitar las supuestas coincidencias de rendimiento asociadas con este enfoque?

Los GUID pueden parecer una opción natural para su clave principal, y si realmente debe hacerlo, probablemente podría argumentar que debe usarla para la PRIMARY KEY de la tabla. Lo que recomiendo encarecidamente que no haga es usar la columna GUID como la clave de clúster , que SQL Server realiza de manera predeterminada, a menos que específicamente le diga que no lo haga.

Realmente necesitas separar dos cuestiones:

  1. la clave primaria es una construcción lógica: una de las claves candidatas que identifica de manera única y fiable cada fila de la tabla. Esto puede ser cualquier cosa, en realidad, una INT , un GUID , una cadena, elija lo que tenga más sentido para su escenario.

  2. la clave de agrupación (la columna o columnas que definen el “índice agrupado” en la tabla): esta es una cuestión relacionada con el almacenamiento físico , y aquí, un tipo de datos pequeño, estable y en constante aumento es su mejor elección: INT o BIGINT como su opción predeterminada.

De forma predeterminada, la clave principal en una tabla de SQL Server también se usa como la clave de clúster, ¡pero eso no tiene por qué ser así! Personalmente, he visto aumentos de rendimiento masivos al dividir la Clave primaria / en clúster basada en GUID anterior en dos claves separadas: la clave primaria (lógica) en el GUID y la clave de agrupación (ordenamiento) en una INT IDENTITY(1,1) separada INT IDENTITY(1,1) columna.

Como Kimberly Tripp , la reina de la indexación, y otros han declarado muchas veces, un GUID ya que la clave de clúster no es óptima, ya que debido a su aleatoriedad generará una fragmentación masiva de páginas e índices y, en general, un mal rendimiento.

Sí, lo sé, hay newsequentialid() en SQL Server 2005 en adelante, pero incluso eso no es verdaderamente secuencial y, por lo tanto, también adolece de los mismos problemas que el GUID , pero un poco menos prominente.

Luego hay otro problema que considerar: la clave de agrupamiento en una tabla se agregará a todas y cada una de las entradas de todos y cada uno de los índices no agrupados en su tabla, por lo que realmente desea asegurarse de que sea lo más pequeña posible. Normalmente, una INT con más de 2 mil millones de filas debería ser suficiente para la gran mayoría de las tablas, y en comparación con un GUID como clave de agrupamiento, puede ahorrarse cientos de megabytes de almacenamiento en el disco y en la memoria del servidor.

Cálculo rápido: utilizando INT frente a GUID como clave principal y de agrupación en clúster:

  • Tabla base con 1’000’000 filas (3.8 MB vs. 15.26 MB)
  • 6 índices no agrupados (22.89 MB vs. 91.55 MB)

TOTAL: 25 MB vs. 106 MB – ¡y eso es solo en una sola mesa!

Algo más para pensar, material excelente de Kimberly Tripp: ¡léelo, léelo de nuevo, digerirlo! Es el evangelio de indexación de SQL Server, realmente.

  • GUID como clave principal y / o clave agrupada
  • El debate sobre el índice agrupado continúa
  • ¡Clave de agrupamiento cada vez mayor: el debate sobre el índice agrupado ………. otra vez!
  • El espacio en disco es barato: ¡ese no es el punto!

PD: por supuesto, si se trata de unos pocos cientos o miles de filas, la mayoría de estos argumentos no tendrán mucho impacto en usted. Sin embargo, si ingresas a las decenas o cientos de miles de filas, o comienzas a contar en millones, entonces esos puntos se vuelven muy cruciales y muy importantes de entender.

Actualización: si desea tener su columna PKGUID como su clave principal (pero no su clave de clúster), y otra columna MYINT ( INT IDENTITY ) como su clave de clúster, utilice esto:

 CREATE TABLE dbo.MyTable (PKGUID UNIQUEIDENTIFIER NOT NULL, MyINT INT IDENTITY(1,1) NOT NULL, .... add more columns as needed ...... ) ALTER TABLE dbo.MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY NONCLUSTERED (PKGUID) CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT) 

Básicamente: solo tiene que decirle explícitamente a la restricción PRIMARY KEY que no está NONCLUSTERED (de lo contrario, se crea como su índice agrupado, de forma predeterminada), y luego crea un segundo índice que se define como CLUSTERED

Esto funcionará, y es una opción válida si tiene un sistema existente que necesita ser “rediseñado” para el rendimiento. Para un sistema nuevo, si comienzas desde cero y no estás en un escenario de replicación, siempre escogería ID INT IDENTITY(1,1) como mi clave principal agrupada, ¡mucho más eficiente que cualquier otra cosa!

He estado utilizando GUIDs como PK desde 2005. En este mundo de bases de datos distribuidas, es absolutamente la mejor manera de fusionar datos distribuidos. Puede disparar y olvidarse de combinar tablas sin preocuparse por la coincidencia de Ints en tablas combinadas. Las uniones de GUID se pueden copiar sin ninguna preocupación.

Esta es mi configuración para usar GUIDs:

  1. PK = GUID. Los GUID se indexan de forma similar a las cadenas, por lo que las tablas de filas más altas (más de 50 millones de registros) pueden necesitar una tabla de particionado u otras técnicas de rendimiento. SQL Server se está volviendo extremadamente eficiente, por lo que las preocupaciones sobre el rendimiento son cada vez menos aplicables.

  2. PK Guid es un índice NO agrupado. Nunca agrupe el índice de un GUID a menos que sea NewSequentialID. Pero incluso entonces, un reinicio del servidor causará interrupciones importantes en el pedido.

  3. Agregue ClusterID Int a cada tabla. Este es su índice CLUSTERED … que ordena su mesa.

  4. Unirme a ClusterIDs (int) es más eficiente, pero trabajo con 20-30 millones de tablas de registros, por lo que unirme a GUID no afecta visiblemente el rendimiento. Si desea un rendimiento máximo, utilice el concepto de ClusterID como su clave principal y únase a ClusterID.

Aquí está mi tabla de correo electrónico …

 CREATE TABLE [Core].[Email] ( [EmailID] UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL, [EmailAddress] NVARCHAR (50) CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL, [CreatedDate] DATETIME CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL, [ClusterID] INT NOT NULL IDENTITY, CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC) ); GO CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID]) GO CREATE UNIQUE NonCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc) 

Si usa GUID como clave principal y crea un índice agrupado, le sugiero que use el valor predeterminado de NEWSEQUENTIALID () para este

Este enlace lo dice mejor que yo y me ayudó en mi toma de decisiones. Por lo general, opto por un int como clave principal, a menos que tenga una necesidad específica de no hacerlo y también dejo que SQL Server autogenere / mantenga este campo a menos que tenga alguna razón específica para no hacerlo. En realidad, las preocupaciones sobre el rendimiento deben determinarse en función de su aplicación específica. Hay muchos factores en juego aquí, incluidos, entre otros, el tamaño de db esperado, la indexación adecuada, consultas eficientes y más. Aunque las personas pueden estar en desacuerdo, creo que en muchos escenarios no notará la diferencia con ninguna de las opciones y debe elegir qué es más apropiado para su aplicación y qué le permite desarrollarse de manera más fácil, rápida y efectiva (si nunca completa la aplicación qué diferencia hace el rest :).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

PD: No estoy seguro de por qué usaría un PK compuesto o qué beneficio cree que le daría.

Actualmente estoy desarrollando una aplicación web con EF Core y aquí está el patrón que uso:

Todas mis clases (tablas) y un int PK y FK. Tengo una columna adicional con el tipo Guid (generado por el constructor c #) con un índice no agrupado.

Todas las uniones de la tabla dentro de EF se gestionan a través de las teclas int mientras que todo el acceso desde el exterior (controladores) se realiza con las Guids.

Esta solución permite no mostrar las claves int en las direcciones URL pero mantener el modelo ordenado y rápido.