使用SqlDataAdapter和SqlCommandBuilder爲sql server創建的更新語句效率低下,如下所述。如何從原始表定義繼承參數大小?
這裏是再現示例代碼: SQL服務器:
Create database TestDB;
GO
USE [TestDB]
CREATE TABLE [dbo].[test](
[i] [int] NOT NULL,
[v] [varchar](50) NULL,
[c] [char](10) NULL,
CONSTRAINT [pk1] PRIMARY KEY CLUSTERED ([i] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
insert into dbo.Test (i,v,c) values (10,'A','B');
GO
C#控制檯應用程序演示代碼:
using System;
using System.Data.SqlClient;
using System.Data;
namespace CmdBuildTest
{
class Program
{
static void Main(string[] args)
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = @"Server=localhost\sql2016;Database=testDB;Trusted_Connection=True;";
SqlDataAdapter da = new SqlDataAdapter("Select * From dbo.test", cn);
//da.FillSchema(ds, SchemaType.Mapped);
SqlCommandBuilder cb = new SqlCommandBuilder(da);
cb.ConflictOption = ConflictOption.OverwriteChanges;
//cb.RefreshSchema();
DataSet ds = new DataSet();
da.Fill(ds);
ds.Tables[0].Rows[0]["v"] = DateTime.UtcNow.Millisecond.ToString();
SqlCommand u = cb.GetUpdateCommand(true);
Console.WriteLine("Update Command: " + u.CommandText);
foreach (SqlParameter par in u.Parameters)
{
Console.WriteLine(" Name=" + par.ParameterName + "|Type=" + par.SqlDbType.ToString() + " |Size=" + par.Size.ToString());
}
da.UpdateCommand = u; //I am not sure if this is required, but I am careful.
//Execute Changes/Update Statement :
da.Update(ds);
Console.ReadLine();
//Sample result in Profiler:
/*
exec sp_executesql N'UPDATE [dbo].[test] SET [v] = @v WHERE (([i] = @Original_i))',N'@v varchar(3),@Original_i int',@v = '603',@Original_i = 1
*/
}
}
}
Console.WriteLine命令顯示創建下列SQL UPDATE語句:
UPDATE [dbo].[test] SET [i] = @i, [v] = @v, [c] = @c WHERE (([i] = @Original_i))
在Sql Profiler中,以下查詢是getti毫無遺漏NG:
exec sp_executesql N'UPDATE [dbo].[test] SET [v] = @v
WHERE (([i] = @Original_i))',N'@v varchar(3),@Original_i int',@v='708',@Original_i=1
現在你可以看到,參數@v被定義爲VARCHAR(3),而在原始表dbo.test列V被定義爲VARCHAR(50)。
由於值708有3個數字,所以傳遞VARCHAR(3)。如果要傳遞一個長度爲5個字符的常量字符串,則參數大小將作爲VARCHAR(5)傳遞。 的行爲是設計說明:這裏:SqlParameter.Size Property如下:「如果沒有明確設定,大小從 指定參數值的實際大小推斷」
我正在尋找一種方法來防止這種情況。正因爲如此,所有通過參數傳遞的變長數據類型的組合都會強制生成一個執行計劃,這導致Sql Server中數千個類似的執行計劃正在被編譯,這些執行計劃需要CPU時間並阻止大量RAM被緩存, -用過的。
如何在不完全重新設計此應用程序的核心代碼的情況下影響此行爲? 我想在這裏做的是不僅從原始表使用CommandBuilder,而且SIZE獲得TYPES,但似乎不可能獲得此信息。
使用的SqlDataAdapter的'FillSchema'方法將爲您提供色譜柱的大小,但在我的測試中這並沒有幫助。即使將這些「MaxLength」值映射回更新命令的參數,查詢計劃仍然會顯示「varchar」列的長度被推斷。 – wablab
是的,這也正是我的發現,同時我也採取了這種方法,但dataadapter的UPDATE方法「銷燬」所有事先準備好的東西...... – Magier