SQL Dinamis - EXEC (@SQL) versus EXEC SP_EXECUTESQL (@SQL)

95

Apa pro dan kontra dunia nyata dari menjalankan perintah SQL dinamis dalam prosedur tersimpan di SQL Server menggunakan

EXEC (@SQL)

melawan

EXEC SP_EXECUTESQL @SQL

?

Mesin Ash
sumber

Jawaban:

96

sp_executesqllebih cenderung mempromosikan penggunaan kembali rencana kueri. Saat menggunakan sp_executesql, parameter secara eksplisit diidentifikasi dalam tanda tangan panggilan. Artikel yang sangat bagus ini menjelaskan proses ini .

Referensi yang sering dikutip untuk banyak aspek sql dinamis adalah Erland Sommarskog's harus membaca: " The Curse and Blessings of Dynamic SQL ".

Mitch Wheat
sumber
21

Hal besar tentang SP_EXECUTESQL adalah memungkinkan Anda membuat kueri berparameter yang sangat baik jika Anda peduli dengan injeksi SQL.

DJ.
sumber
1
Saya tidak berpikir Anda dapat membuat parameter sql dinamis tanpa itu ??
DJ.
EXEC ('SELECT * FROM FOO WHERE ID =?', 123) akan menggantikan parameter placeholder "?" dengan nilai 123 dan kemudian jalankan kueri, mengembalikan hasil untuk SELECT * FROM FOO WHERE ID = 123
Peter Wone
1
Ups, sintaks itu hanya tersedia untuk server yang ditautkan.
Peter Wone
1
Benar-benar salah satu alasan terbesar untuk menggunakan sp_executesql jika membuat kueri secara dinamis untuk mencegah injeksi sql.
Steven Rogers
5

Artikel Microsoft's Using sp_executesql merekomendasikan penggunaan sp_executesqlalih-alih executepernyataan.

Karena prosedur tersimpan ini mendukung substitusi parameter , sp_executesql lebih fleksibel daripada EXECUTE; dan karena sp_executesql menghasilkan rencana eksekusi yang kemungkinan besar akan digunakan kembali oleh SQL Server, sp_executesql lebih efisien daripada EXECUTE.

Jadi, take away: Jangan gunakan executepernyataan . Gunakan sp_executesql.

Gan
sumber
7
Takeaway Anda tidak selalu berlaku. Ada kalanya tidak ada bonus efisiensi dengan menggunakan sp_executesql, tetapi Anda dapat melindungi kode Anda dari serangan sql injection. Kadang-kadang Anda tidak bisa menggunakan sp_executesql seperti Anda dapat menggunakan exec, jadi ... seseorang berkata - tidak ada solusi yang tepat. Saya setuju.
OzrenTkalcecKrznaric
Ya, Microsoft seharusnya menempatkannya sebagai "lebih mungkin untuk menjadi efisien". Dan berada di industri selama beberapa tahun, saya telah melihat kasus-kasus di mana sp_executesqltidak dapat digunakan untuk menggantikan execute. Mungkin saya harus menempatkan poin yang saya coba tekankan sebagai: Gunakan sp_executesqlalih-alih execute bila memungkinkan .
Gan
2

Saya akan selalu menggunakan sp_executesql hari ini, semua itu sebenarnya adalah pembungkus untuk EXEC yang menangani parameter & variabel.

Namun jangan lupa tentang OPSI RECOMPILE saat menyelaraskan kueri pada database yang sangat besar, terutama jika Anda memiliki data yang tersebar di lebih dari satu database dan menggunakan CONSTRAINT untuk membatasi pemindaian indeks.

Kecuali Anda menggunakan OPTION RECOMPILE, SQL server akan mencoba membuat rencana eksekusi "satu ukuran cocok untuk semua" untuk kueri Anda, dan akan menjalankan pemindaian indeks penuh setiap kali dijalankan.

Ini jauh lebih tidak efisien daripada seek, dan artinya ini berpotensi memindai seluruh indeks yang dibatasi ke rentang yang bahkan tidak Anda tanyakan: @

Ten98
sumber
-2
  1. Deklarasikan variabel tersebut
  2. Setel dengan perintah Anda dan tambahkan bagian dinamis seperti gunakan nilai parameter sp (di sini @IsMonday dan @IsTuesday adalah parameter sp)
  3. jalankan perintahnya

    declare  @sql varchar (100)
    set @sql ='select * from #td1'
    
    if (@IsMonday+@IsTuesday !='')
    begin
    set @sql= @sql+' where PickupDay in ('''+@IsMonday+''','''+@IsTuesday+''' )'
    end
    exec( @sql)
Sara
sumber
15
Ini terbuka untuk injeksi SQL, jika Anda meletakkan misalnya "a '; DROP DATABASE DATABASE_NAME; GO;';" dalam variabel @IsMonday
Erik A. Brandstadmoen
apakah rentan terhadap injuction sql jika @IsMonday int?
Vikas Rana
@VikasRana @IsRana @IsRaDay tidak dapat berada intdalam SQL dinamis. Perhatikan bahwa @sql dideklarasikan sebagai varcharataunvarchar
Weihui Guo