トレースdapper.NETのソースコード- SQL文字列のコントローラーを間違ってスローの効率とメモリリークを引き起こす
GithubのリンクTrace-Dapper.NET-Source-Code
ここでは、dapperによって使用される重要な概念です.ITS
なぜ、SQL文字列がキーの1つとして使われているのか、単純にマッピング型のハンドルを使うのではなく
最も直接的な解決方法は、異なるSQL文字列ごとに異なる動的メソッドを確立し、異なるキャッシュに保存することです.
たとえば、次のコードは単純なクエリ動作ですが、Dapperキャッシュの数は画像表示など999999に達しました
この問題を回避するには、原則を維持する必要があります
例えば、SQL文字列をスプライスする必要がある場合は、文字列を使用するのが効率的です
この時、dapperは
まず、ソースコードgetcacheinfoの下でGetReitalTokensメソッドをトレースすると、キャッシュDapperがデータを取得する前に
これは、置換タイミングがsetParameter Dynamicメソッドであるため、キャッシュ
また、文字列置換方法でもある.
11 . SQL文字列が間違っていると、効率が悪くなりメモリリークが発生します
ここでは、dapperによって使用される重要な概念です.ITS
SQL string
キャッシュする重要なキー値の一つです.別のSQL文字列が使用されている場合、Dapperはこれに対して新しいダイナミックメソッドとキャッシュを作成しますcan also cause slow query & memory leaks
.なぜ、SQL文字列がキーの1つとして使われているのか、単純にマッピング型のハンドルを使うのではなく
order of query column
. 前述のように、dapperは「result convert to code」
動的メソッドを作成する方法fixed
, 異なるSQL SELECT列の順序で動的メソッドの同じセットを使用しないでくださいA column value to b column
間違った値の問題.最も直接的な解決方法は、異なるSQL文字列ごとに異なる動的メソッドを確立し、異なるキャッシュに保存することです.
たとえば、次のコードは単純なクエリ動作ですが、Dapperキャッシュの数は画像表示など999999に達しました
using (var cn = new SqlConnection(@"connectionString"))
{
for ( int i = 0; i < 999999 ; i ++ )
{
var guid = Guid.NewGuid();
for (int i2 = 0; i2 < 2; i2++)
{
var result = cn.Query<User>($"select '{guid}' ").First();
}
}
}
この問題を回避するには、原則を維持する必要があります
Reuse SQL string
, 最も簡単な方法はparametrization
, たとえば、上記のコードを次のコードに変更すると、キャッシュの数が1
, 再利用の目的を達成するためにusing (var cn = new SqlConnection(@"connectionString"))
{
for ( int i = 0; i < 999999 ; i ++ )
{
var guid = Guid.NewGuid();
for (int i2 = 0; i2 < 2; i2++)
{
var result = cn.Query<User>($"select @guid ",new { guid}).First();
}
}
}
12 . Dapper SQLの正しい文字列表記方法:文字列置換
例えば、SQL文字列をスプライスする必要がある場合は、文字列を使用するのが効率的です
fixed values
.この時、dapperは
Literal Replacements
関数の使い方{=Attribute_Name}
設定する値文字列を置換し、その値をパラメータに保存します.void Main()
{
using (var cn = Connection)
{
var result = cn.Query("select N'Wei' Name,26 Age,{=VipLevel} VipLevel", new User{ VipLevel = 1}).First();
}
}
13 .リテラル置換がキャッシュ問題を回避する理由は?
まず、ソースコードgetcacheinfoの下でGetReitalTokensメソッドをトレースすると、キャッシュDapperがデータを取得する前に
SQL string
その試合{=Attribute_Name}
役割private static readonly Regex literalTokens = new Regex(@"(?<![\p{L}\p{N}_])\{=([\p{L}\p{N}_]+)\}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);
internal static IList<LiteralToken> GetLiteralTokens(string sql)
{
if (string.IsNullOrEmpty(sql)) return LiteralToken.None;
if (!literalTokens.IsMatch(sql)) return LiteralToken.None;
var matches = literalTokens.Matches(sql);
var found = new HashSet<string>(StringComparer.Ordinal);
List<LiteralToken> list = new List<LiteralToken>(matches.Count);
foreach (Match match in matches)
{
string token = match.Value;
if (found.Add(match.Value))
{
list.Add(new LiteralToken(token, match.Groups[1].Value));
}
}
return list.Count == 0 ? LiteralToken.None : list;
}
次に、CreateParaminfoGeneratorメソッドでパラメーターパラメーター化された動的メソッドを生成します.このセクションのメソッドILは以下の通りです.IL_0000: ldarg.1
IL_0001: castclass <>f__AnonymousType1`1[System.Int32]
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: callvirt System.Data.IDataParameterCollection get_Parameters()/System.Data.IDbCommand
IL_000d: pop
IL_000e: ldarg.0
IL_000f: ldarg.0
IL_0010: callvirt System.String get_CommandText()/System.Data.IDbCommand
IL_0015: ldstr "{=VipLevel}"
IL_001a: ldloc.0
IL_001b: callvirt Int32 get_VipLevel()/<>f__AnonymousType1`1[System.Int32]
IL_0020: stloc.1
IL_0021: ldloca.s V_1
IL_0023: call System.Globalization.CultureInfo get_InvariantCulture()/System.Globalization.CultureInfo
IL_0028: call System.String ToString(System.IFormatProvider)/System.Int32
IL_002d: callvirt System.String Replace(System.String, System.String)/System.String
IL_0032: callvirt Void set_CommandText(System.String)/System.Data.IDbCommand
IL_0037: ret
次に、マッピングの動的メソッドを生成します.この論理を理解するために、ここでシミュレーションの例を示します.public static class DbExtension
{
public static IEnumerable<User> Query(this DbConnection cnn, string sql, User parameter)
{
using (var command = cnn.CreateCommand())
{
command.CommandText = sql;
CommandLiteralReplace(command, parameter);
using (var reader = command.ExecuteReader())
while (reader.Read())
yield return Mapping(reader);
}
}
private static void CommandLiteralReplace(IDbCommand cmd, User parameter)
{
cmd.CommandText = cmd.CommandText.Replace("{=VipLevel}", parameter.VipLevel.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
private static User Mapping ( IDataReader reader )
{
var user = new User();
var value = default(object);
value = reader[0];
if(!(value is System.DBNull))
user.Name = (string)value;
value = reader[1];
if (!(value is System.DBNull))
user.Age = (int)value;
value = reader[2];
if (!(value is System.DBNull))
user.VipLevel = (int)value;
return user;
}
}
上記の例を読んだ後に、dapperリテラル置換の基礎となる原理はstring replace
それは文字列の方法にも属します.キャッシュ問題はなぜ回避できるかこれは、置換タイミングがsetParameter Dynamicメソッドであるため、キャッシュ
SQL Key is unchanged
同じSQL文字列とキャッシュを再利用できます.また、文字列置換方法でもある.
only support basic value type
文字列型を使用する場合、システムはあなたに通知しますThe type String is not supported for SQL literals.
SQL注入問題を避けるために.Reference
この問題について(トレースdapper.NETのソースコード- SQL文字列のコントローラーを間違ってスローの効率とメモリリークを引き起こす), 我々は、より多くの情報をここで見つけました https://dev.to/shps951023/trace-dapper-net-source-code-fast-efficiency-key-cache-principle-2g5bテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol