Mis desarrolladores han configurado su aplicación para usar GUID como PK para casi todas sus tablas y, de forma predeterminada, SQL Server ha configurado el índice agrupado en estas PK.
El sistema es relativamente joven y nuestras tablas más grandes tienen poco más de un millón de filas, pero estamos analizando nuestra indexación y queremos poder escalar rápidamente, ya que puede ser necesario en el futuro cercano.
Por lo tanto, mi primera inclinación fue mover el índice agrupado al campo creado, que es una gran representación de DateTime. Sin embargo, la única forma en que puedo hacer que el CX sea único sería incluir la columna GUID en este CX, pero ordenar por creado primero.
¿Esto haría que la clave de agrupamiento fuera demasiado amplia y aumentaría el rendimiento de las escrituras? Las lecturas también son importantes, pero las escrituras son probablemente una preocupación mayor en este momento.
newsequentialid
son aleatorios. Las claves agrupadas son mejores cuando son estrechas y crecientes. Un GUID es lo contrario: gordo y aleatorio. Imagine una estantería casi llena de libros. Entra el OED y debido a la aleatoriedad de las guías, se inserta en el medio del estante. Para mantener las cosas ordenadas, la mitad correcta de los libros tiene que ser introducida en una nueva ubicación, que es una tarea que requiere mucho tiempo. Eso es lo que el GUID está haciendo a su base de datos y está matando el rendimiento.Respuestas:
Los principales problemas con los GUID, especialmente los no secuenciales, son:
Entonces, ¿qué significa esto para su situación? Todo se reduce a tu diseño. Si su sistema se trata simplemente de escrituras y no le preocupa la recuperación de datos, entonces el enfoque descrito por Thomas K es preciso. Sin embargo, debe tener en cuenta que al seguir esta estrategia, está creando muchos problemas potenciales para leer esos datos y almacenarlos. Como señala Jon Seigel , también estarás ocupando más espacio y esencialmente teniendo memoria hinchada.
La pregunta principal sobre los GUID es qué tan necesarios son. A los desarrolladores les gustan porque aseguran la singularidad global, pero es una rara ocasión que este tipo de singularidad sea necesaria. Pero considere que si su número máximo de valores es menor a 2,147,483,647 (el valor máximo de un entero con signo de 4 bytes), entonces probablemente no esté usando el tipo de datos apropiado para su clave. Incluso utilizando BIGINT (8 bytes), su valor máximo es 9,223,372,036,854,775,807. Esto suele ser suficiente para cualquier base de datos no global (y muchas globales) si necesita algún valor de incremento automático para una clave única.
Finalmente, en lo que respecta al uso de un montón versus un índice agrupado, si solo está escribiendo datos, un montón sería más eficiente porque está minimizando la sobrecarga para las inserciones. Sin embargo, los montones en SQL Server son extremadamente ineficientes para la recuperación de datos. Mi experiencia ha sido que un índice agrupado siempre es deseable si tiene la oportunidad de declarar uno. He visto que la adición de un índice agrupado a una tabla (más de 4 mil millones de registros) mejora el rendimiento general de selección en un factor de 6.
Información Adicional:
fuente
No hay nada malo con GUID como claves y clústeres en un sistema OLTP (a menos que tenga MUCHOS índices en la tabla que sufran el aumento del tamaño del clúster). De hecho, son mucho más escalables que las columnas IDENTITY.
Existe una creencia generalizada de que los GUID son un gran problema en SQL Server; en gran medida, esto es simplemente incorrecto. De hecho, el GUID puede ser significativamente más escalable en cajas con más de aproximadamente 8 núcleos:
Lo siento, pero sus desarrolladores tienen razón. Preocúpese por otras cosas antes de preocuparse por GUID.
Ah, y finalmente: ¿por qué quieres un índice de clúster en primer lugar? Si su preocupación es un sistema OLTP con muchos índices pequeños, probablemente sea mejor con un montón.
Consideremos ahora qué fragmentación (que introducirá el GUID) hace a sus lecturas. Hay tres problemas principales con la fragmentación:
Dado que su preocupación en la pregunta es sobre la escalabilidad, que podemos definir como "Agregar más hardware hace que el sistema vaya más rápido", estos son sus problemas menores. Para abordar cada uno a su vez
Anuncio 1) Si desea escalar, puede comprar E / S. Incluso un SSD Samsung / Intel 512GB barato (a unos pocos USD / GB) te dará más de 100K IOPS. No lo consumirá pronto en un sistema de 2 sockets. Y si te encuentras con eso, compra uno más y listo
Anuncio 2) Si elimina en su tabla, tendrá páginas semillenas de todos modos. E incluso si no lo hace, la memoria es barata y para todos menos los sistemas OLTP más grandes: los datos activos deberían encajar allí. Buscar empacar más datos en páginas es una suboptimización cuando busca escala.
Anuncio 3) Una tabla construida a partir de datos divididos en páginas con frecuencia altamente fragmentados realiza E / S aleatorias exactamente a la misma velocidad que las tablas llenas secuencialmente
Con respecto a la unión, hay dos tipos principales de unión que probablemente verá en una OLTP como la carga de trabajo: Hash y loop. Veamos cada uno a su vez:
Hash join: una combinación hash supone que la tabla pequeña se escanea y la más grande normalmente se busca. Es muy probable que las tablas pequeñas estén en la memoria, por lo que la E / S no es su preocupación aquí. Ya hemos mencionado el hecho de que las búsquedas tienen el mismo costo en un índice fragmentado que en un índice no fragmentado.
Unión de bucle: se buscará la tabla externa. Mismo costo
Es posible que también tenga muchos escaneos de tablas incorrectos, pero luego GUID nuevamente no es su preocupación, la indexación adecuada sí lo es.
Ahora, puede tener algunos escaneos de rango legítimos (especialmente cuando se une a claves externas) y en este caso, los datos fragmentados están menos "empaquetados" en comparación con los datos no fragmentados. Pero consideremos qué combinaciones es probable que vea en datos bien indexados de 3NF:
Una combinación de una tabla que tiene una referencia de clave externa a la clave principal de la tabla a la que hace referencia
Al revés
Anuncio 1) En este caso, irá por una sola búsqueda a la clave principal: unir n a 1. Fragmentación o no, el mismo costo (una búsqueda)
Anuncio 2) En este caso, se está uniendo a la misma clave, pero puede recuperar más de una fila (búsqueda de rango). La unión en este caso es de 1 a n. Sin embargo, en la tabla extranjera que busca, está buscando la misma clave, que es probable que esté en la misma página en un índice fragmentado que en una no fragmentada.
Considere esas claves foráneas por un momento. Incluso si hubiera colocado "perfectamente" secuencialmente nuestras claves principales, cualquier cosa que apunte a esa clave seguirá siendo no secuencial.
Por supuesto, es posible que se esté ejecutando en una máquina virtual en alguna SAN en algún banco que tenga poco dinero y mucho proceso. Entonces todos estos consejos se perderán. Pero si ese es su mundo, la escalabilidad probablemente no sea lo que está buscando: busca rendimiento y alta velocidad / costo, que son dos cosas diferentes.
fuente
Thomas: algunos de tus puntos tienen mucho sentido y estoy de acuerdo con todos ellos. Si usa SSD, el saldo de lo que optimiza cambia. Aleatorio versus secuencial no es la misma discusión que el disco giratorio.
Estoy especialmente de acuerdo en que adoptar una vista de DB pura es terriblemente incorrecto. Hacer que su aplicación sea lenta y no escalable para mejorar solo el rendimiento de la base de datos puede ser bastante errónea.
El gran problema con IDENTITY (o secuencia, o cualquier cosa generada en el DB) es que es terriblemente lento, ya que requiere un viaje de ida y vuelta al DB para crear una clave, y esto automáticamente crea un cuello de botella en su DB, obliga a que las aplicaciones deben hacer una llamada a DB para comenzar a usar una clave. La creación de un GUID resuelve esto mediante el uso de la aplicación para crear la clave, se garantiza que sea globalmente único (por definición) y, por lo tanto, las capas de la aplicación pueden usarlo para pasar el registro ANTES de incurrir en un DB ida y vuelta.
Pero tiendo a usar una alternativa a los GUID. Mi preferencia personal para un tipo de datos aquí es un BIGINT globalmente único generado por la aplicación. ¿Cómo se hace para hacer esto? En el ejemplo más trivial, agrega una función pequeña, MUY liviana a su aplicación para hash un GUID. Asumiendo que su función hash es rápida y relativamente rápida (consulte CityHash de Google para ver un ejemplo: http://google-opensource.blogspot.in/2011/04/introducing-cityhash.html - asegúrese de obtener todos los pasos de compilación correctamente, o la variante FNV1a de http://tools.ietf.org/html/draft-eastlake-fnv-03 para código simple) esto le brinda el beneficio de identificadores únicos generados por la aplicación y un valor clave de 64 bits con el que las CPU funcionan mejor .
Hay otras formas de generar BIGINT, y en estos dos algos existe la posibilidad de colisiones hash: leer y tomar decisiones conscientes.
fuente