2009-06-22 23 views
19

Tengo un procedimiento almacenado que funciona con una gran cantidad de datos. Tengo esos datos insertados en una tabla temporal. El flujo global de acontecimientos es algo así comoCreando una clave principal en una tabla temporal - ¿Cuándo?

CREATE #TempTable (
    Col1 NUMERIC(18,0) NOT NULL, --This will not be an identity column. 
    ,Col2 INT NOT NULL, 
    ,Col3 BIGINT, 

    ,Col4 VARCHAR(25) NOT NULL, 
    --Etc... 

    -- 
    --Create primary key here? 
) 


INSERT INTO #TempTable 
SELECT ... 
FROM MyTable 
WHERE ... 

INSERT INTO #TempTable 
SELECT ... 
FROM MyTable2 
WHERE ... 

-- 
-- ...or create primary key here? 

Mi pregunta es ¿cuándo es el mejor momento para crear una clave principal en mi mesa #temptable? Teoricé que debería crear la restricción/índice de la clave principal después de insertar todos los datos porque el índice debe reorganizarse a medida que se crea la información de la clave principal. Pero me di cuenta de que mi suposición subyacente podría estar equivocada ...

En caso de que sea relevante, los tipos de datos que utilicé son reales. En la tabla #TempTable, Col1 y Col4 estarán formando mi clave principal.

Actualización: En mi caso, estoy duplicar la clave principal de las tablas de origen. Sé que los campos que conformarán mi clave principal siempre serán únicos. No me preocupa una tabla de modificaciones fallidas si agrego la clave principal al final.

Sin embargo, esto a un lado, mi pregunta sigue en pie, ¿cuál es más rápido suponiendo que ambos tendrían éxito?

P.S. Lo siento si esto es un duplicado. Es lo suficientemente básico como para ser, pero no he podido encontrar nada parecido.

Respuesta

14

Esto depende mucho.

Si hace que el índice de clave principal se agrupe después de la carga, toda la tabla se volverá a escribir ya que el índice agrupado no es realmente un índice, es el orden lógico de los datos. Su plan de ejecución en las inserciones dependerá de los índices vigentes cuando se determine el plan, y si el índice agrupado está en su lugar, se ordenará antes de la inserción. Por lo general, verá esto en el plan de ejecución.

Si convierte la clave principal en una restricción simple, será un índice regular (no agrupado) y la tabla simplemente se rellenará en el orden que el optimizador determine y el índice actualizado.

Creo que el rendimiento general más rápido (de este proceso para cargar tablas temporales) suele ser escribir los datos como un montón y luego aplicar el índice (no agrupado).

Sin embargo, como han señalado otros, la creación del índice podría fallar. Además, la tabla temporal no existe aisladamente. Es de suponer que hay un mejor índice para leer los datos de él para el siguiente paso. Este índice deberá estar en su lugar o creado. En este es donde hay que sacrificar la velocidad aquí para obtener confiabilidad (aplique primero el PK y cualquier otra restricción) y la velocidad más tarde (tenga al menos el índice agrupado en su lugar si va a tener uno).

+1

Interesante. Gracias. Servicial. ¿Podrías expandirte con algunos ejemplos quizás? –

+0

@Cade, para el índice agrupado, se refiere al orden físico en el disco, no al orden lógico (las tablas no tienen un orden lógico). –

+1

No, el orden físico en el disco puede ser cualquier cosa. El índice agrupado es simplemente los datos almacenados en las hojas en un índice btree en lugar de en un montón. Todavía puede haber fragmentación en SQL Server y en el disco. –

3

También puede crear la clave primaria antes de las inserciones: si la clave primaria está en una columna de identidad, las inserciones se realizarán secuencialmente de todos modos y no habrá diferencia.

+0

No utilizaré la identidad. Publicaste esto mientras estaba actualizando mi pregunta. Mi clave principal consistirá en los campos NUMERIC (18,0) y VARCHAR (25). –

+0

Las claves principales están agrupadas de manera predeterminada. Esto ordenará su orden secuencial de los datos en función de los valores PK. Estoy de acuerdo con esta respuesta, debe suceder antes de insertar. También tenga en cuenta: si agrega índices adicionales no agrupados. Crear una PK agrupada después haría que SQL Server reconstruya los índices no agrupados. – DBAndrew

0

No creo que se hace ninguna diferencia significativa en su caso:

  • ya sea que paga la pena un poco a la vez, con cada solo inserto
  • o tendrá que pagar una mayor penal después de todas las inserciones se realizan, pero sólo una vez

cuando se crea por adelantado antes de que comiencen las inserciones, se podría potencialmente atrapar violaciónes de PK a medida que se han insertado los datos, si el valor de PK no es creado por el sistema

Pero aparte de eso, no es una gran diferencia, de verdad.

Marc

+1

¿Se divide la extensión y el registro y esas cosas? Esto no necesita ser tenido en cuenta? –

1

Si se agrega la clave principal al crear la tabla, la primera inserción será libre (no hay comprobaciones necesarias.) El segundo inserto sólo tiene que ver si es diferente de la primera. El tercer inserto debe verificar dos filas, y así sucesivamente. Los controles serán búsquedas de índice, porque hay una restricción única en su lugar.

Si agrega la clave principal después de todas las inserciones, cada fila debe coincidir con cada una de las filas. Así que supongo que agregar una clave principal desde el principio es más barato.

Pero tal vez Sql Server tiene una forma muy inteligente de comprobar la singularidad. Entonces, si quieres estar seguro, ¡mídelo!

+0

No pensé en eso ... eso está bien. –

0

No estaba planeando responder a esto, ya que no estoy 100% seguro de mi conocimiento de esto.Pero dado que no parece que obtenga mucha respuesta ...

Según tengo entendido, un PK es un índice único y cuando inserta cada registro, su índice se actualiza y optimiza. Entonces ... si agrega los datos primero, luego cree el índice, el índice solo se optimiza una vez.

Por lo tanto, si está seguro de que sus datos están limpios (sin duplicar los datos PK), entonces diría insertar, luego agregue el PK.

Pero si sus datos pueden tener datos PK duplicados, yo diría que crear el PK primero, por lo que se bombardeará lo antes posible.

+0

Gracias por su respuesta. De hecho, estoy seguro de que no tendré un problema con los duplicados ... –

1

Aún más importante que las consideraciones de rendimiento, si no está ABSOLUTAMENTE, 100% seguro de que tendrá valores únicos insertados en la tabla, primero cree la clave principal. De lo contrario, no se podrá crear la clave principal.

Esto le impide insertar datos duplicados/incorrectos.

+0

Esto no es un problema para mí. Entiendo que podría ser para algunos, pero no es un problema para mí. –

+0

Creo que esto tiene sentido simplemente porque demuestra lo que lógicamente está tratando de hacer más claramente y permite que el motor lo ayude cuando supuestos que solían ser seguros (es decir, la certeza de que no habrá datos duplicados en la tabla después del inserto) ya no son seguros (por ejemplo, como resultado de algún cambio en una parte diferente de la base de datos). – binki

6

Si el modelo de recuperación de su base de datos se establece en simple o en bloque, SELECCIONE ... EN ... UNION ALL puede ser la solución más rápida. SELECT .. INTO es una operación masiva y las operaciones masivas están mínimamente registradas.

por ejemplo:

-- first, create the table 
SELECT ... 
INTO #TempTable 
FROM MyTable 
WHERE ... 
UNION ALL 
SELECT ... 
FROM MyTable2 
WHERE ... 

-- now, add a non-clustered primary key: 
-- this will *not* recreate the table in the background 
-- it will only create a separate index 
-- the table will remain stored as a heap 
ALTER TABLE #TempTable ADD PRIMARY KEY NONCLUSTERED (NonNullableKeyField) 

-- alternatively: 
-- this *will* recreate the table in the background 
-- and reorder the rows according to the primary key 
-- CLUSTERED key word is optional, primary keys are clustered by default 
ALTER TABLE #TempTable ADD PRIMARY KEY CLUSTERED (NonNullableKeyField) 

De lo contrario, Cade Roux tenía un buen consejo re: antes o después.

1

Me preguntaba si podría mejorar un procedimiento almacenado muy "caro" que implica un montón de comprobaciones en cada inserción en las tablas y me encontré con esta respuesta. En Sproc, varias tablas temporales se abren y se referencian entre sí. Agregué la clave principal a la instrucción CREATE TABLE (aunque mis selecciones usan sentencias WHERE NOT EXISTS para insertar datos y asegurar la exclusividad) y mi tiempo de ejecución se redujo SEVERAMENTE. Recomiendo usar las teclas principales. Siempre al menos pruébalo incluso cuando creas que no lo necesitas.

+1

El contexto de la pregunta era menos sobre si crear una clave principal o no, pero en qué momento es más eficiente: población de datos previos o población de datos posteriores. La conclusión previa a esta pregunta fue que una clave/índice ayudó con el tiempo de ejecución. –

Cuestiones relacionadas