13

データベースに Web サービスの呼び出しを記録する必要があります。最初に、コード ファースト EF を使用してエンティティ クラスを定義し、データベース スクリプトを生成しました。データベース部分は非常にシンプルで、テーブルは 1 つだけです。Id という主キーがあり、他の列は string 、datetime および float です。全部で16列。

次に、VS2012 のパフォーマンス分析を実行しました。レポートは、RecordUsageEF が呼び出し全体の半分の時間を消費していることを示しています。これはばかげています。MergeOption.NoTracking オプションと Pre-Generate Views( How to: Pre-Generate Views to Improvement Query Performance )を試しました。しかし、それらはあまり役に立ちませんでした。

次に、Ado.net を試してみました。テスト用にSQLスクリプトをソースコードに入れました。2 つのメソッドを一緒に呼び出してパフォーマンスを比較します。

    public static void RecordUsage(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {                                                                                               
        RecordUsageEF(httpContext, processedRecipe, orgRecipe, userName, action, trueview, pageId);
        RecordUsageADO(httpContext, processedRecipe, orgRecipe, userName, action, trueview, pageId);
    }

結果は私を驚かせました:
ここに画像の説明を入力

静的 EF コンテキストを使用して更新すると、次のように改善されます。
ここに画像の説明を入力

RecordUsageEF の内部:
ここに画像の説明を入力

内部 RecordUsageEF の更新-- 静的コンテキスト
ここに画像の説明を入力

更新 デフォルトのパフォーマンスが CPU サンプリングであることに気付きました。インストルメンテーションを選択したときの結果は次のとおりです。
ここに画像の説明を入力

それほど悪くはありませんが、CPU が Web サイト/Web サービスのボトルネックである場合。EFは良い選択ではないようです。

SQLプロファイラーでEFによって生成されたスクリプトを確認しました。これは非常に単純な挿入 SQL ステートメントであり、Ado.net ステートメントよりも高速に実行されました。

EFで見逃したものはありますか? このレベルのパフォーマンスでは、EF を使用できません。

ここにソースコードがあります。
EF バージョン:

public static readonly LogContainer container = new LogContainer();

private static void RecordUsageEF(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {
        {
            container.Usages.MergeOption = System.Data.Objects.MergeOption.NoTracking;
            using (LookupService ls = new LookupService(httpContext.Server.MapPath(geoDBLocation), LookupService.GEOIP_MEMORY_CACHE))
            {
                //get country of the ip address
                Location location = s.getLocation(httpContext.Request.UserHostAddress);


                Usage usage = new Usage()
                {
                    Brand = brand,
                    Action = action.ToString(),
                    ExecuteDate = DateTime.Now,
                    OutputFormat = trueview ? Path.GetExtension(processedRecipe.Output.trueview_file) : Path.GetExtension(processedRecipe.Output.design_file),
                    Recipe = orgRecipe,
                    SessionId = pageId,
                    Username = userName,
                    ClientIP = httpContext.Request.UserHostAddress,
                    ClientCountry = location == null ? null : location.countryName,
                    ClientState = location == null ? null : location.regionName,
                    ClientCity = location == null ? null : location.city,
                    ClientPostcode = location == null ? null : location.postalCode,
                    ClientLatitude = location == null ? null : (double?)location.latitude,
                    ClientLongitude = location == null ? null : (double?)location.longitude,
                    UserAgent = httpContext.Request.UserAgent
                };

                //container.AddToUsages(usage);
                container.Usages.AddObject(usage);                   
                container.SaveChanges(System.Data.Objects.SaveOptions.None);
            }
        }     
    }

EF 設定がデフォルトです。
ここに画像の説明を入力

Ado.net バージョン:

    private static void RecordUsageADO(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {
        using (SqlConnection conn = new SqlConnection("data source=pgo_swsvr;initial catalog=OESDWebSizer;user id=sa;password=sa;MultipleActiveResultSets=True;"))
        {

            using (LookupService ls = new LookupService(httpContext.Server.MapPath(geoDBLocation), LookupService.GEOIP_MEMORY_CACHE))
            {
                //get country of the ip address
                //test using "203.110.131.5"  "58.63.236.236"
                //httpContext.Request.UserHostAddress
                Location location = ls.getLocation(httpContext.Request.UserHostAddress);


                SqlCommand command = new SqlCommand();
                conn.Open();
                command.Connection = conn;
                command.CommandType = System.Data.CommandType.Text;
                command.CommandText = @"insert into Usages ([Brand],[Username],[SessionId],[Action],[Recipe],[ExecuteDate]
                                       ,[OutputFormat],[ClientIP],[ClientCountry],[ClientState],[ClientCity],[ClientPostcode]
                                       ,[ClientLatitude],[ClientLongitude],[UserAgent])
                                        Values ('" + brand + "'," 
                                        + (string.IsNullOrEmpty(userName) ? "NULL" : "'" + userName + "'") + ", '" + pageId + "', '" + action.ToString() + "', '" + orgRecipe + "', '" + DateTime.Now.ToString("yyyyMMdd") + "', '"
                                        + (trueview ? Path.GetExtension(processedRecipe.Output.trueview_file) : Path.GetExtension(processedRecipe.Output.design_file)) + "', '"
                                        + httpContext.Request.UserHostAddress + "', '"
                                        + (location == null ? string.Empty : location.countryName) + "', '"
                                        + (location == null ? string.Empty : location.regionName) + "', '"
                                        + (location == null ? string.Empty : location.city) + "', '"
                                        + (location == null ? string.Empty : location.postalCode) + "', "
                                        + (location == null ? 0 : (double?)location.latitude) + ", "
                                        + (location == null ? 0 : (double?)location.longitude) + ", '"
                                        + httpContext.Request.UserAgent + "')";

                command.ExecuteNonQuery();

            }
        }
    }
4

2 に答える 2

2

Entity Frameworkは、(一部の)CPUパフォーマンスのコストとして多くの詳細を抽象化しています。Microsoftには、パフォーマンスに関する考慮事項の詳細が記載された記事があります。 パフォーマンスに関する考慮事項(Entity Framework)

于 2012-08-03T16:04:54.083 に答える
1

私はほとんどの場合、コード ファーストの方法に精通していますが、コンテナー オブジェクトが DbContext である場合、次のようにすると、挿入のパフォーマンスが劇的に向上するはずです。

container.Configuration.AutoDetectChangesEnabled = false;
container.Configuration.ValidateOnSaveEnabled = false;
于 2012-08-01T02:04:45.213 に答える