2010-05-18 11 views
21

Tengo un proyecto que implica registrar datos de un dispositivo directamente en una tabla sql.Cómo hacer inserciones muy rápidas en SQL Server 2008

me hacen muy poco procesamiento en el código antes de escribir en SQL Server (2008 expreso por cierto)

Me suelen utilizar método ExecuteNonQuery de la clase sqlhelper y pasar el nombre de procedimiento almacenado y la lista de parámetros que el SP espera .

Esto es muy conveniente, pero necesito una forma mucho más rápida de hacerlo.

Gracias.

+0

tengo que registrar cada salida de una en una, no puedo recoger varias salidas y les conectarse mayor –

Respuesta

37

ExecuteNonQuery con una instrucción INSERT, o incluso un procedimiento almacenado, te llevará a miles de insertos por segundo rango en Express. 4000-5000/seg son fáciles de conseguir, lo sé con certeza.

Lo que generalmente ralentiza las actualizaciones individuales es el tiempo de espera para el registro de descarga y debe tener en cuenta eso. La solución más fácil es simplemente realizar un lote de compromiso. P.ej. cometer cada 1000 inserciones, o cada segundo. Esto llenará las páginas de registro y amortizará el costo de la descarga de registros de flujo de espera sobre todas las inserciones en una transacción.

Con las confirmaciones por lotes, probablemente acumule rendimiento de escritura en el registro del disco, lo cual no hay nada que pueda hacer al respecto, salvo cambiar el hardware (ir a incursión 0 bandas en el registro).

Si tocas cuellos de botella anteriores (improbable), entonces puedes ver las declaraciones de procesamiento por lotes, es decir. envíe un solo lote de T-SQL con múltiples inserciones en él. Pero esto rara vez vale la pena.

Por supuesto, tendrá que reducir al mínimo el tamaño de sus textos, lo que significa reducir el ancho de su tabla a las columnas mínimamente necesarias, eliminar los índices no agrupados, eliminar las restricciones innecesarias. Si es posible, use un Heap en lugar de un índice agrupado, ya que las inserciones de Heap son significativamente más rápidas que las indexadas en clúster.

Hay poca necesidad de utilizar la interfaz de inserción rápida (es decir, SqlBulkCopy). Al usar inserciones ordinarias y ExecuteNoQuery en las confirmaciones de lotes, agotarás el rendimiento de escritura secuencial de la unidad mucho más rápido que la necesidad de implementar la inserción masiva. Se necesita una inserción masiva en máquinas conectadas SAN rápidas, y usted menciona Express, por lo que probablemente no sea el caso. Existe una percepción de lo contrario por ahí, pero es simplemente porque la gente no se da cuenta de que la inserción masiva les da un compromiso por lotes, y es la confirmación por lotes que acelera la idea, no la inserción masiva.

Como con cualquier prueba de rendimiento, asegúrese de eliminar la aleatoriedad, y asignar previamente la base de datos y el registro de, que no quieren golpear dB o registro de eventos de crecimiento durante las mediciones de prueba o durante la producción, es taaan aficionado.

+0

lol @ "eso es tan amateur ..." @Ramus - Gracias, hombre, lo has conseguido. Por favor, aclare en "ExecuteNonQuery". ¿Te refieres al método ExecuteNonQuery en la clase sqlhelper en Microsoft.ApplicationBlocks.Data? –

+0

Me refiero a SqlCommand básico http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery.aspx, pero creo que Application Framework es muy similar en todos los aspectos. Uno piensa que debe asegurarse de que Application Framework * * no inscriba su conexión en una transacción distribuida, que simplemente hundiría cualquier rendimiento. –

+0

gracias. Usaré el comando sqlcommand –

4

inserción masiva sería el más rápido, ya que se registra mínimamente

.NET también tiene la SqlBulkCopy Class

+0

Tengo que registrar cada salida una En un momento, no puedo recopilar varias salidas y registrarlas a granel. –

2

lo general, esto se hace por medio de un BULK INSERT. Básicamente, usted prepara un archivo y luego emite la declaración BULK INSERT y SQL Server copia todos los datos del archivo en la tabla con el método rápido posible.

Tiene algunas restricciones (por ejemplo, no hay forma de hacer el tipo de comportamiento "actualizar o insertar" si tiene filas posiblemente existentes para actualizar), pero si puede evitarlas, entonces es poco probable para encontrar algo mucho más rápido.

+0

Tengo que registrar la salida de cada dispositivo individualmente, que excluye las opciones masivas –

+0

¿Qué quiere decir con "registrar la salida de cada dispositivo individualmente"? –

+0

lo que quiero decir es que tengo que registrar cada salida de a una por vez, no puedo recopilar varias salidas y registrarlas a granel –

1

Si se refiere a continuación, utilizar .NET SqlBulkCopy

+1

tengo que registrar cada salida del dispositivo de forma individual, que excluye las opciones masivas –

+0

@CharlesO: No tengo idea de qué eso significa. ¡Bulk no tiene relación con muchos dispositivos! –

+0

lo que quiero decir es que tengo que registrar cada salida de a una por vez, no puedo recopilar varias salidas y registrarlas en grandes cantidades. Los índices –

2

cosas que pueden ralentizar inserciones incluyen índices y lee o actualizaciones (cerraduras) en la misma mesa. Puede acelerar situaciones como la suya evitando ambas e insertando transacciones individuales en una tabla de espera separada sin índices u otra actividad. Luego, agrupe la mesa de espera en la mesa principal con un poco menos de frecuencia.

+1

también pueden ayudar a acelerar los INSERTOS. Como cualquier cosa con un DB, depende ... –

+0

@Mitch: Esto es nuevo para mí, ¿nos puede dar un ejemplo? – Aaronaught

+0

@Joel: Su sugerencia tiene sentido. Básicamente, mantengo abierta una conexión ADO.net y sigo usando los objetos sqlcommand para insertar registros tan rápido como el dispositivo los produce. Sin embargo: 1) ¿Serán las inserciones sql en bruto una mejor opción que utilizar un proceso almacenado en este caso? 2) ¿Necesitará esta tabla de mantenimiento tener un índice agrupado, como un ID de incremento automático col 3) decir que ejecuto un script sqlAgent cada 2 segundos para agrupar la tabla de espera en la tabla principal, no las eliminará la mesa de espera después de copiar cada lote degrada aún más el rendimiento? Gracias –

1

Realmente solo puede ir tan rápido como se ejecutará su SP. Asegúrese de que las tablas estén correctamente indexadas y, si tiene un índice agrupado, asegúrese de que tenga una clave creciente estrecha y única. Asegúrese de que los índices y restricciones restantes (si los hay) no tengan demasiados gastos generales.

No debería ver demasiada sobrecarga en la capa ADO.NET (no usaría necesariamente ninguna otra biblioteca .NET encima de SQLCommand). Puede utilizar los métodos Async de ADO.NET para poner en cola varias llamadas al proceso almacenado sin bloquear un solo hilo en su aplicación (esto podría liberar más rendimiento que cualquier otra cosa, al igual que tener varias máquinas insertadas en la base de datos)

Aparte de eso, realmente necesita decirnos más acerca de sus requisitos.

+0

sugerencia sólida, adhiérase solo a ADO.net puro, y posiblemente mantenga mi conexión abierta el mayor tiempo posible. Construir los parámetros para el SP y luego llamar al SP y pasar los parámetros, parece tedioso para una simple operación de inserción. ¿Recomendaría enviar declaraciones de inserción directamente desde ADO.net? –

+0

@CharlesO - Utilizaría SQLCommand, agregaría los parámetros y ExecuteNonQuery (no enviaría la cadena literal 'INSERT INTO blah VALUES (blah')) - y definitivamente pensaría en usar la versión asincrónica: BeginExecuteNonQuery (http: // msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx) con algún tipo de gobernador sobre cuántas inserciones activas y una cola interna al programa. Luego puede ver si puede manejar su carga de trabajo esperada o si necesita un almacenamiento y reenvío más extenso. –

2

Aquí es una buena manera de insertar una gran cantidad de registros utilizando las variables de tabla ...

... pero lo mejor limitarlo a 1000 registros a la vez porque son las variables de tabla "en la Memoria"

en este ejemplo voy a insertar 2 registros en una tabla con 3 campos - CustID, nombre, apellido

--first create an In-Memory table variable with same structure 
--you could also use a temporary table, but it would be slower 

declare @MyTblVar table (CustID int, FName nvarchar(50), LName nvarchar(50)) 

insert into @MyTblVar values (100,'Joe','Bloggs') 

insert into @MyTblVar values (101,'Mary','Smith') 

Insert into MyCustomerTable 

Select * from @MyTblVar 
+1

¿Es esto realmente más eficiente que insertar directamente en una tabla de base de datos? (Esa es una pregunta genuina, no una crítica ...) –