2010-08-20 8 views
6

Tenemos una base de datos heredada que es un servidor sql db (2005 y 2008).Sql Server Legacy Database To Clustered index o no

Todas las claves principales en las tablas son UniqueIdentifiers.

Las tablas actualmente no tienen un índice agrupado creado en ellas y estamos teniendo problemas de rendimiento en tablas con solo 750k registros. Esta es la primera base de datos en la que he trabajado con identificadores únicos como la única clave principal y nunca he visto que el servidor sql sea tan lento con la devolución de datos.

No deseo crear un índice agrupado en el identificador único ya que no son secuenciales y, por lo tanto, desacelerarán las aplicaciones cuando se trata de insertar datos.

No podemos eliminar el identificador único ya que se utiliza para fines de gestión de identidad de registro de sitio remoto.

Pensé en agregar una gran columna de identidad entera a las tablas y crear el índice agrupado en esta columna e incluir la columna de identificador único.

es decir

int identidad - La primera columna para mantener la pieza de inserción acelera identificador único - Para garantizar la aplicación sigue funcionando como se espera.

El objetivo es mejorar la consulta de identidad y el rendimiento de la consulta de tablas unidas.

Q1: ¿Mejorará el rendimiento de la consulta de la base de datos o se ralentizará?

Q2: ¿Hay alguna alternativa a esto que no haya enumerado?

Gracias Pete

Editar: El rendimiento de los problemas están en la recuperación de datos de forma rápida a través de sentencias de selección, especialmente si algunos de los más "transaccional/cambiantes" tablas se unen entre sí.

Edición 2: El combinaciones entre tablas son por lo general lo que entre la clave principal y clave externa, para las tablas que tienen las claves externas que se incluyen en el índice no agrupado para proporcionar un índice más cubriente.

Todas las tablas no tienen otros valores que proporcionen un buen índice agrupado.

Me inclino más por agregar una columna de identidad adicional en cada una de las tablas de alta carga y luego incluir la columna Guid PK actual dentro del índice agrupado para proporcionar el mejor rendimiento de consulta.

Editar 3: Me gustaría estimar que el 80% de las consultas se realizan solo en claves primarias y externas a través del mecanismo de acceso a datos. En general, nuestro modelo de datos tiene objetos cargados perezosos que realizan la consulta cuando se accede, estas consultas usan el identificador de objetos y la columna PK. Tenemos una gran cantidad de consultas de exclusión/inclusión de datos impulsadas por el usuario que utilizan las columnas de clave externa como un filtro basado en los criterios de para que el tipo X excluya los siguientes identificadores. El 20% restante es donde las cláusulas en Enum (int) o columnas de rango de fechas, muy pocas consultas basadas en texto se realizan en el sistema.

Siempre que sea posible, he agregado índices de cobertura para cubrir las consultas más pesadas, pero todavía estoy decepcionado por el rendimiento. Como bluefooted dice que los datos se almacenan como un montón.

+0

¿Actualmente tiene un índice no agrupado en los identificadores únicos? – jwsample

+0

Sí, tenemos índices no agrupados en los identificadores únicos. – Peter

+0

Dado que tiene al menos un índice en esa columna, ya está incurriendo en una penalización de rendimiento en la inserción. Dependiendo de la estructura de la tabla, puede ser capaz de soltar el índice no agrupado y cambiar a agrupado con poco impacto a lo que está viendo actualmente. – jwsample

Respuesta

4

Si no tiene un índice agrupado en la tabla, se está almacenando como un montón en lugar de un b-tree. El acceso a los datos de Heap es absolutamente atroz en SQL Server, por lo que definitivamente necesita agregar un índice agrupado.

Estoy de acuerdo con su análisis de que la columna GUID es una mala elección para la agrupación, especialmente porque no tiene la capacidad de utilizar NEWSEQUENTIALID(). Podría crear una nueva clave de entero artificial si lo desea, pero si hay otra columna o combinación de columnas que tendría sentido como índice agrupado, también está bien.

¿Tiene un campo que se utiliza con frecuencia para escaneos de rango? ¿Qué columnas se usan para las uniones? ¿Hay una combinación de columnas que también identifique de manera única la fila aparte del GUID? Publicar una muestra del modelo de datos nos ayudaría a sugerir un buen candidato para la agrupación.

+0

Azul lamentablemente no puedo publicar el modelo de datos ya que mi empresa es extremadamente estricta cuando se trata de este tipo de cosas. En algunas tablas, hay columnas de fecha que se utilizan para escaneos de rango. En general, las claves primarias (guids) y foreign keys (guids) se utilizan para las uniones, no hay ninguna unión en las columnas de texto sin formato. Me preguntaba sobre el uso de la fecha de creación, pero acabo de agregar eso en la última versión y, por lo tanto, no todas las filas tienen este valor. Creo que agregar la clave entera artificial con la identidad activada es la ruta que tomaré. El guid es el PK en cada mesa. – Peter

+0

La fecha es a menudo un buen candidato para una clave de agrupamiento, especialmente si las consultas están frecuentemente restringidas por rango de fechas. Si acaba de agregarlo, supongo que no se utiliza con demasiada frecuencia, pero al menos con la fecha de creación puede garantizar la inserción ordenada y, por lo tanto, minimizar las divisiones de páginas y la fragmentación. Mi única preocupación sobre la clave artificial es que probablemente nunca será útil a menos que cambie su modelo de datos para unirse a la nueva clave en lugar de al GUID. –

+0

Independientemente de lo que termine eligiendo, asegúrese de examinar también sus índices no agrupados. Si su índice GUID contiene solo la columna GUID, puede que no sea terriblemente útil. Es posible que desee investigar agregar algunas columnas a la cláusula INCLUDE para cubrir sus consultas más comunes. –

2

No estoy seguro de dónde provienen sus GUID, pero si se generan durante la inserción, usar NEWSEQUENTIALID() en SQL Server en lugar de NEWID() lo ayudará a evitar problemas de fragmentación durante la inserción.

En cuanto a la elección de un índice agrupado, como Kimberly L. Tripp afirma here: "los factores más importantes al elegir un índice agrupado son que es único, estrecho y estático (cada vez mayor tiene otros beneficios para minimizar las divisiones). " Un GUID no cumple con el requisito estrecho en comparación con un INT o incluso BIGINT.

Kimberly también tiene un excelente artículo en GUIDs as PRIMARY KEYs and/or the clustering key.

+0

Los identificadores se generan a través de .Net Frameworks Guid.NewGuid(); ya que la arquitectura de este sistema se construyó para que los objetos generen su propia identificación. (De nuevo, un sistema heredado.) – Peter

0

No indica cuáles son sus problemas de rendimiento. Si la acción de peor rendimiento es un INSERT, entonces tal vez su solución sea la correcta. Si se trata de otra cosa, analizaré cómo el índice agrupado puede ayudar.

Puede consultar los índices existentes en la tabla y las consultas que los utilizan. Puede seleccionar un índice que, aunque degrada INSERT ligeramente, proporciona un mayor beneficio a las áreas de problemas de rendimiento actuales.

+0

Tienes razón bob. Edité la publicación. Los problemas surgen cuando consultamos más tablas transaccionales (es decir, las que cambian más que las tablas estáticas). Esto se complica si unimos varias tablas transaccionales juntas. – Peter

1

No es 100% claro para mí: ¿es su patrón de acceso número 1 para consultar las tablas por el GUID o por otras columnas? Y cuando se une a otras tablas, ¿qué columnas (y tipos de datos) se usan con más frecuencia?

Realmente no puedo darle recomendaciones sólidas hasta que entiendo más acerca de cómo se usan estos GUID. Me doy cuenta de que dijiste que son claves principales, pero eso no garantiza que se utilicen como las condiciones principales para las consultas o en las uniones.

ACTUALIZACIÓN

Ahora que sé un poco más, tengo una sugerencia loca. Agrupe esas tablas en los GUID, pero establezca el factor de relleno en 60%. Esto mejorará el problema de división de página y le dará un mejor rendimiento al consultar sobre esos cachorros.

En cuanto a usar Guid.NewGuid(), parece que puede hacer secuencialGUID en C# después de todo. He encontrado el siguiente código aquí en SO:

[DllImport("rpcrt4.dll", SetLastError = true)] 
static extern int UuidCreateSequential(out Guid guid); 

public static Guid SequentialGuid() 
{ 
    const int RPC_S_OK = 0; 
    Guid g; 
    if (UuidCreateSequential(out g) != RPC_S_OK) 
     return Guid.NewGuid(); 
    else 
     return g; 
} 

NEWSEQUENTIALID() es en realidad un contenedor para UuidCreateSequential.Estoy seguro de que si no puede usar esto directamente en el cliente, puede encontrar una manera de hacer un viaje de ida y vuelta rápido al servidor para obtener una nueva ID secuencial desde allí, tal vez incluso con una tabla de "dispensador" y una procedimiento almacenado para hacer el trabajo.

+0

He editado la publicación original, vea edición 2 y 3. – Peter

+0

El factor de relleno definitivamente es una posibilidad, aunque nuevamente va a hinchar su índice. Tener claves GUID en su índice agrupado no es ideal, pero como ya está atrapado con los GUID y se utilizan para la mayoría de sus combinaciones, es posible que tenga que ir con eso. Creo que es necesario hacer algunas pruebas para descubrir la mejor manera. ¿Tiene un sistema de prueba que puede usar para probar los diferentes métodos? –

+0

Estoy de acuerdo en que es horrible usar esos enormes GUID, y reducir el número de filas por página reduciendo el factor de relleno es desafortunado, pero si quiere un rendimiento de actualización mejorado a costa del rendimiento de lectura, ese es el camino a seguir. Ni siquiera es una proposición tan directa porque las divisiones de página ya reducen la densidad de fila de la página ... – ErikE

Cuestiones relacionadas