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

Masalah dengan kinerja parameter nilai tabel

Jika TVP "terasa lebih lambat" daripada opsi lainnya, kemungkinan besar Anda tidak menerapkannya dengan benar.

  1. Anda tidak boleh menggunakan DataTable, kecuali aplikasi Anda menggunakannya di luar pengiriman nilai ke TVP. Menggunakan IEnumerable<SqlDataRecord> antarmuka lebih cepat dan menggunakan lebih sedikit memori karena Anda tidak menduplikasi koleksi dalam memori hanya untuk mengirimkannya ke DB. Saya telah mendokumentasikan ini di tempat-tempat berikut:
  2. Anda tidak boleh menggunakan AddWithValue untuk SqlParameter, meskipun ini sepertinya bukan masalah kinerja. Tapi tetap harus:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured);
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection);
    
  3. TVP adalah Variabel Tabel dan karena itu tidak memelihara statistik. Artinya, mereka melaporkan hanya memiliki 1 baris ke Query Optimizer. Jadi, di proc Anda, baik:
    • Gunakan kompilasi ulang tingkat pernyataan pada kueri apa pun menggunakan TVP untuk apa pun selain SELECT sederhana:OPTION (RECOMPILE)
    • Buat tabel sementara lokal (yaitu satu # ) dan salin konten TVP ke tabel temp
    • Anda dapat mencoba menambahkan kunci utama yang dikelompokkan ke Jenis Tabel Buatan Pengguna
    • Jika menggunakan SQL Server 2014 atau yang lebih baru, Anda dapat mencoba menggunakan tabel In-Memory OLTP/memori yang dioptimalkan. Silakan lihat:Tabel temp dan variabel tabel lebih cepat dengan menggunakan optimasi memori

Mengenai mengapa Anda melihat:

insert into @data ( ... fields ... ) values ( ... values ... )
-- for each row
insert into @data ( ... fields ... ) values ( ... values ... )

bukannya:

insert into @data ( ... fields ... ) 
values ( ... values ... ),
       ( ... values ... ),

JIKA memang itu yang terjadi, maka:

  • Jika penyisipan dilakukan dalam suatu Transaksi maka tidak ada perbedaan kinerja yang nyata
  • Sintaks daftar nilai yang lebih baru (yaitu VALUES (row1), (row2), (row3) ) terbatas pada sekitar 1000 baris dan karenanya bukan opsi yang layak untuk TVP yang tidak memiliki batas itu. NAMUN, ini sepertinya bukan alasan penggunaan sisipan individual, mengingat tidak ada batasan saat melakukan tab INSERT INTO @data (fields) SELECT tab.[col] FROM (VALUES (), (), ...) tab([col]) , yang saya dokumentasikan di sini:Jumlah Maksimum Baris untuk Konstruktor Nilai Tabel . Sebaliknya...
  • Alasannya kemungkinan besar karena melakukan penyisipan individual memungkinkan streaming nilai dari kode aplikasi ke SQL Server:
    1. menggunakan iterator (yaitu IEnumerable<SqlDataRecord> disebutkan di #1 di atas), kode aplikasi mengirimkan setiap baris seperti yang dikembalikan dari metode, dan
    2. membuat VALUES (), (), ... list, bahkan jika melakukan INSERT INTO ... SELECT FROM (VALUES ...) pendekatan (yang tidak terbatas pada 1000 baris), yang masih memerlukan pembuatan seluruh VALUES daftar sebelum mengirim apa saja dari data ke SQL Server. Jika ada banyak data, itu akan memakan waktu lebih lama untuk membuat string yang sangat panjang, dan akan memakan lebih banyak memori saat melakukannya.

Silakan lihat juga whitepaper 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. Menggunakan INNER JOIN untuk Menggabungkan Tabel SQL Server dan Menampilkannya di ASP.NET Webforms

  2. Menghapus nol di depan dari bidang dalam pernyataan SQL

  3. Permintaan Linq tidak berperilaku seperti yang diharapkan

  4. T-SQL:Ekspor ke file Excel baru

  5. SQL Server:String Kosong VS Null