Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Bagaimana saya bisa memasukkan 10 juta catatan dalam waktu sesingkat mungkin?

Tolong jangan jangan buat DataTable untuk memuat melalui BulkCopy. Itu adalah solusi yang baik untuk kumpulan data yang lebih kecil, tetapi sama sekali tidak ada alasan untuk memuat 10 juta baris ke dalam memori sebelum memanggil database.

Taruhan terbaik Anda (di luar BCP / BULK INSERT / OPENROWSET(BULK...) ) adalah mengalirkan konten dari file ke database melalui Parameter Bernilai Tabel (TVP). Dengan menggunakan TVP Anda dapat membuka file, membaca baris &mengirim baris hingga selesai, lalu menutup file. Metode ini memiliki jejak memori hanya satu baris. Saya menulis sebuah artikel, Streaming Data Ke SQL Server 2008 Dari Aplikasi, yang memiliki contoh skenario ini.

Gambaran sederhana dari struktur tersebut adalah sebagai berikut. Saya mengasumsikan tabel impor dan nama bidang yang sama seperti yang ditunjukkan pada pertanyaan di atas.

Objek database yang diperlukan:

-- First: You need a User-Defined Table Type
CREATE TYPE ImportStructure AS TABLE (Field VARCHAR(MAX));
GO

-- Second: Use the UDTT as an input param to an import proc.
--         Hence "Tabled-Valued Parameter" (TVP)
CREATE PROCEDURE dbo.ImportData (
   @ImportTable    dbo.ImportStructure READONLY
)
AS
SET NOCOUNT ON;

-- maybe clear out the table first?
TRUNCATE TABLE dbo.DATAs;

INSERT INTO dbo.DATAs (DatasField)
    SELECT  Field
    FROM    @ImportTable;

GO

Kode aplikasi C# untuk menggunakan objek SQL di atas ada di bawah. Perhatikan bagaimana daripada mengisi objek (misalnya DataTable) dan kemudian mengeksekusi Stored Procedure, dalam metode ini eksekusi Stored Procedure yang memulai pembacaan konten file. Parameter input dari Stored Proc bukan variabel; ini adalah nilai kembalian dari suatu metode, GetFileContents . Metode itu dipanggil ketika SqlCommand memanggil ExecuteNonQuery , yang membuka file, membaca baris dan mengirimkan baris ke SQL Server melalui IEnumerable<SqlDataRecord> dan yield return konstruksi, dan kemudian menutup file. Prosedur Tersimpan hanya melihat Variabel Tabel, @ImportTable, yang dapat diakses segera setelah data mulai masuk (catatan:data bertahan untuk waktu yang singkat, meskipun bukan konten lengkap, dalam tempdb ).

using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using Microsoft.SqlServer.Server;

private static IEnumerable<SqlDataRecord> GetFileContents()
{
   SqlMetaData[] _TvpSchema = new SqlMetaData[] {
      new SqlMetaData("Field", SqlDbType.VarChar, SqlMetaData.Max)
   };
   SqlDataRecord _DataRecord = new SqlDataRecord(_TvpSchema);
   StreamReader _FileReader = null;

   try
   {
      _FileReader = new StreamReader("{filePath}");

      // read a row, send a row
      while (!_FileReader.EndOfStream)
      {
         // You shouldn't need to call "_DataRecord = new SqlDataRecord" as
         // SQL Server already received the row when "yield return" was called.
         // Unlike BCP and BULK INSERT, you have the option here to create a string
         // call ReadLine() into the string, do manipulation(s) / validation(s) on
         // the string, then pass that string into SetString() or discard if invalid.
         _DataRecord.SetString(0, _FileReader.ReadLine());
         yield return _DataRecord;
      }
   }
   finally
   {
      _FileReader.Close();
   }
}

GetFileContents metode di atas digunakan sebagai nilai parameter input untuk Prosedur Tersimpan seperti yang ditunjukkan di bawah ini:

public static void test()
{
   SqlConnection _Connection = new SqlConnection("{connection string}");
   SqlCommand _Command = new SqlCommand("ImportData", _Connection);
   _Command.CommandType = CommandType.StoredProcedure;

   SqlParameter _TVParam = new SqlParameter();
   _TVParam.ParameterName = "@ImportTable";
   _TVParam.TypeName = "dbo.ImportStructure";
   _TVParam.SqlDbType = SqlDbType.Structured;
   _TVParam.Value = GetFileContents(); // return value of the method is streamed data
   _Command.Parameters.Add(_TVParam);

   try
   {
      _Connection.Open();

      _Command.ExecuteNonQuery();
   }
   finally
   {
      _Connection.Close();
   }

   return;
}

Catatan tambahan:

  1. Dengan beberapa modifikasi, kode C# di atas dapat disesuaikan untuk mengelompokkan data.
  2. Dengan sedikit modifikasi, kode C# di atas dapat disesuaikan untuk mengirim dalam beberapa bidang (contoh yang ditampilkan dalam artikel "Mengukus Data..." yang ditautkan di atas lolos dalam 2 bidang).
  3. Anda juga dapat memanipulasi nilai setiap record di SELECT pernyataan dalam proses.
  4. Anda juga dapat memfilter baris dengan menggunakan kondisi WHERE dalam proc.
  5. Anda dapat mengakses Variabel Tabel TVP beberapa kali; ini HANYA BACA tetapi tidak "hanya untuk meneruskan".
  6. Kelebihan dari SqlBulkCopy :
    1. SqlBulkCopy hanya INSERT sedangkan menggunakan TVP memungkinkan data digunakan dengan cara apa pun:Anda dapat memanggil MERGE; Anda dapat DELETE berdasarkan beberapa kondisi; Anda dapat membagi data menjadi beberapa tabel; dan seterusnya.
    2. Karena TVP tidak hanya INSERT, Anda tidak memerlukan tabel staging terpisah untuk memasukkan data.
    3. Anda bisa mendapatkan kembali data dari database dengan memanggil ExecuteReader bukannya ExecuteNonQuery . Misalnya, jika ada IDENTITY bidang pada DATAs impor tabel, Anda dapat menambahkan OUTPUT klausa ke INSERT untuk mengirimkan kembali INSERTED.[ID] (dengan asumsi ID adalah nama IDENTITY bidang). Atau Anda dapat meneruskan kembali hasil kueri yang sama sekali berbeda, atau keduanya karena beberapa set hasil dapat dikirim dan diakses melalui Reader.NextResult() . Mendapatkan info kembali dari database tidak dimungkinkan saat menggunakan SqlBulkCopy namun ada beberapa pertanyaan di sini di S.O. orang yang ingin melakukan hal itu (setidaknya berkaitan dengan IDENTITY yang baru dibuat nilai).
    4. Untuk info lebih lanjut tentang mengapa terkadang lebih cepat untuk keseluruhan proses, meskipun sedikit lebih lambat dalam mendapatkan data dari disk ke SQL Server, silakan lihat buku putih ini dari Tim Penasihat Pelanggan SQL Server:Memaksimalkan Throughput dengan TVP


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dapatkan Daftar Akun Email Database di SQL Server (T-SQL)

  2. Kembalikan Kunci Utama dari Server Tertaut di SQL Server (Contoh T-SQL)

  3. Tugas SSIS untuk impor jumlah kolom yang tidak konsisten?

  4. MultipleActiveResultSets=Benar atau beberapa koneksi?

  5. Kesalahan JDBC SQL Server di Java 8:Pengandar tidak dapat membuat sambungan aman ke SQL Server dengan menggunakan enkripsi Secure Sockets Layer (SSL)