2010-01-29 15 views
9

¿Cómo llamo a procedimientos almacenados al por mayor? Me gustaría hacer algo como una copia masiva.Procedimiento almacenado a granel SQL llame a C#

Todo lo que hace el procedimiento almacenado es 8 selecciones para restricción única y 8 inserciones. Sin valor de retorno

Respuesta

7

No puede hacer eso.

La copia masiva es un volcado de datos en una tabla, no se puede llamar a sprocs o cualquier otra cosa en lugar de simplemente verterlo en una tabla existente.

Lo que puede hacer, sin embargo, es volcar los datos usando copia masiva en una tabla temporal con la estructura correcta, y luego llamar a su sproc que mueve esos datos a las tablas reales, posiblemente modificando datos existentes en vez de insertar eso, o lo que sea.

+0

¿Es esa una solución elegante? ¿Qué sucedería si tuviera que cambiar el parámetro del procedimiento almacenado a una matriz y disparar como 1000 objetos a la vez, y hacer que el procedimiento almacenado recorra la matriz? – Will

+1

¿Por qué no lo intentas y ves? Si ambas soluciones funcionan, las llamaría elegantes ya que ninguna de ellas parece problemática en teoría.Para mí, con mi conocimiento, sería más fácil hacer bulk-copy + sproc en lugar de múltiples sprocs con matrices, ya que no lo he hecho, pero deberías probarlo. Tú eres el que tiene que mantener el código, así que solo tú sabes lo que será mejor para ti. Me gustaría ver las características de rendimiento también y realmente no puedo decir si uno sería mucho mejor que el otro. –

+1

Curioso: ¿cuál funcionó mejor para ti? (¿Desechar todo en una tabla temporal, en lugar de "fragmentar" las actualizaciones y que el proceso almacenado acepte matrices?) – poundifdef

1

Si desea cargar datos a granel en una tabla (inserciones), la clase SqlBulkCopy es el camino a seguir.

Como alternativa, puede usar el SqlDataAdapter. Establezca InsertCommand en el procedimiento almacenado que realizará una inserción y asigne los campos de tabla de datos a los parámetros de sproc. Si tiene registros actualizados en la tabla de datos, también puede especificar un UpdateCommand que se activará para cada fila actualizada. A continuación, llame al método Update en SqlDataAdapter pasando la tabla de datos. Puede establecer la propiedad UpdateBatchSize para definir cuántos registros se enviarán al db en cada ida y vuelta.

0

Los procedimientos almacenados SqlServer pueden aceptar xml, por lo que podría preparar sus datos masivos como un archivo xml y pasarlos a un procedimiento almacenado de propósito especial que luego llamaría a su procedimiento almacenado original para cada fila. Necesitarías la función OPENXML.

Dudo en recomendar las características xml de SqlServer, pero este puede ser un caso en el que sean apropiadas.

4

Si está utilizando SQL Server 2008, entonces Table-Valued Parameters es una opción viable.

En primer lugar, se crea un user-defined table type que contiene todas sus columnas esperados y los tipos de datos en el lado de SQL Server:

create type dbo.MyTableType as table 
( 
    foo int, 
    bar varchar(100) 
); 

a continuación, utilizar lo anterior como el parámetro de tipo de tabla para su procedimiento almacenado:

create procedure uspInsertMyBulkData 
(
    @myTable dbo.MyTableType readonly 
) 
as 
    /* now in here you can use the multi-row data from the passed-in table 
     parameter, @myTable, to do your selects and inserts*/  

Luego, en el lado del cliente C#/.NET, llame a este procedimiento almacenado a través de ADO.NET y pase un DataTable, un objeto que hereda de DbDataReader (como DataTableReader) o un objeto de tipo IEnumerable<SqlDataRecord>:

// create my source DataTable 
object [] row1 = {1, "a"}; 
object [] row2 = {2, "b"}; 
var myDataTable = new DataTable(); 
myDataTable.Columns.Add(new DataColumn("foo")); 
myDataTable.Columns.Add(new DataColumn("bar")); 
myDataTable.LoadDataRow(row1, true); 
myDataTable.LoadDataRow(row2, true); 

// bulk send data to database 
var conn = new SqlConnection(connectionString); 
var cmd = new SqlCommand("uspInsertMyBulkData", conn) 
    { 
     CommandType = CommandType.StoredProcedure 
    }; 
SqlParameter param = cmd.Parameters.AddWithValue("@myTable", myDataTable); 
param.SqlDbType = SqlDbType.Structured; 
cmd.ExecuteNonQuery(); 
+0

[Este] (http://technet.microsoft.com/es-es/library/bb510489.aspx) es un buen ejemplo para crear un Parámetro con valores de tabla como variable de entrada del procedimiento almacenado ... –

+0

Intenté este enfoque. Cuando inserto 14 millones de valores 'int' de columna única en ese' DataTable', consume 2GB de mi RAM y es extremadamente largo. Mientras que, en teoría, 14M 'int's es solo 14m * 4 = 56m. El DataTable crea demasiada sobrecarga. – AgentFire

0

No estoy diciendo que lo recomiendo, pero se podría poner un desencadenador de inserción en la tabla que está copiando a granel en que se inserta en las 8 mesas separadas en vez de la original. Es posible que necesite una tempdb lo suficientemente grande como para almacenar todos los datos ...

CREATE TRIGGER TRG_REPLACETRIGGER 
    ON BULK_TABLE 
    INSTEAD OF INSERT 
AS BEGIN 
    INSERT TABLE1 (ID, VALUE) SELECT ID, VALUE1 FROM INSERTED 
    INSERT TABLE2 (ID, VALUE) SELECT ID, VALUE2 FROM INSERTED 
    -- ... TABLE3-7 
    INSERT TABLE8 (ID, VALUE) SELECT ID, VALUE8 FROM INSERTED 
END 
Cuestiones relacionadas