SqlDataAdapterとSqlCommandBuilderを使用すると、SQL Server用に作成された更新ステートメントは、以下で説明するように非効率的です。ここで元のテーブル定義からパラメータサイズを継承する方法は?
は、再生のためのサンプルコードは、次のとおりです。 SQL Serverの:
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プロファイラでは、次のクエリはgetti cought ngの:オリジナルテーブルの列VはVARCHAR(50)のように定義されてdbo.testながら
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は、(3)VARCHARとして定義されます。
値708が3桁であるため、VARCHAR(3)が渡されます。定数文字列を5文字で渡すと、パラメータ・サイズはVARCHAR(5)として渡されます。 動作は、ここで説明し、設計によってれる:「明示的に設定されていない場合は、サイズが 指定されたパラメータ値の実際のサイズから推測されます。」
:SqlParameter.Size Propertyを次のように
私は実際にそれを防ぐ方法を探しています。このため、パラメータとして渡される可変長データ型のすべての組み合わせが生成された単一の実行計画を強制するため、Sql Server内で数千の類似の実行計画が生成され、CPU時間が消費され、大量のRAMがキャッシュされる-中古。
このアプリケーションのコアコードを完全に再設計しなければ、この動作にどのような影響がありますか? 私がここでやりたいのは、元のテーブルからCommandBuilderを使用してTYPEを取得するだけでなく、SIZEを取得することですが、この情報を取得することは不可能です。
列のサイズを提供しますが、私のテストではこれは役に立ちません。それらの「MaxLength」値を更新コマンドのパラメータにマッピングしても、クエリプランは依然として、「varchar」列の長さが推測されることを示している。 – wablab
はい、まさに私の発見でもありますが、私はこのアプローチをしばらく行っていましたが、データアダプターのUPDATEメソッドは事前に準備されたすべてを "破壊"します... – Magier