Entity Framework Table Per Type Performance

早过忘川 提交于 2020-01-12 19:05:51

问题


So it turns out that I am the last person to discover the fundamental floor that exists in Microsoft's Entity Framework when implementing TPT (Table Per Type) inheritance.

Having built a prototype with 3 sub classes, the base table/class consisting of 20+ columns and the child tables consisting of ~10 columns, everything worked beautifully and I continued to work on the rest of the application having proved the concept. Now the time has come to add the other 20 sub types and OMG, I've just started looking the SQL being generated on a simple select, even though I'm only interested in accessing the fields on the base class.

This page has a wonderful description of the problem.

Has anyone gone into production using TPT and EF, are there any workarounds that will mean that I won't have to: a) Convert the schema to TPH (which goes against everything I try to achieve with my DB design - urrrgghh!)? b) rewrite with another ORM?

The way I see it, I should be able to add a reference to a Stored Procedure from within EF (probably using EFExtensions) that has the the TSQL that selects only the fields I need, even using the code generated by EF for the monster UNION/JOIN inside the SP would prevent the SQL being generated every time a call is made - not something I would intend to do, but you get the idea.

The killer I've found, is that when I'm selecting a list of entities linked to the base table (but the entity I'm selecting is not a subclass table), and I want to filter by the pk of the Base table, and I do .Include("BaseClassTableName") to allow me to filter using x=>x.BaseClass.PK == 1 and access other properties, it performs the mother SQL generation here too.

I can't use EF4 as I'm limited to the .net 2.0 runtimes with 3.5 SP1 installed.

Has anyone got any experience of getting out of this mess?


回答1:


We've hit this same problem and are considering porting our DAL from EF4 to LLBLGen because of this.

In the meantime, we've used compiled queries to alleviate some of the pain:

Compiled Queries (LINQ to Entities)

This strategy doesn't prevent the mammoth queries, but the time it takes to generate the query (which can be huge) is only done once.

You'll can use compiled queries with Includes() as such:

static readonly Func<AdventureWorksEntities, int, Subcomponent> subcomponentWithDetailsCompiledQuery = CompiledQuery.Compile<AdventureWorksEntities, int, Subcomponent>(
       (ctx, id) => ctx.Subcomponents
            .Include("SubcomponentType")
            .Include("A.B.C.D")
            .FirstOrDefault(s => s.Id == id));

    public Subcomponent GetSubcomponentWithDetails(int id)
    {
        return subcomponentWithDetailsCompiledQuery.Invoke(ObjectContext, id);
    }



回答2:


This seems a bit confused. You're talking about TPH, but when you say:

The way I see it, I should be able to add a reference to a Stored Procedure from within EF (probably using EFExtensions) that has the the TSQL that selects only the fields I need, even using the code generated by EF for the monster UNION/JOIN inside the SP would prevent the SQL being generated every time a call is made - not something I would intend to do, but you get the idea.

Well, that's Table per Concrete Class mapping (using a proc rather than a table, but still, the mapping is TPC...). The EF supports TPC, but the designer doesn't. You can do it in code-first if you get the CTP.

Your preferred solution of using a proc will cause performance problems if you restrict queries, like this:

var q = from c in Context.SomeChild
        where c.SomeAssociation.Foo == foo
        select c;

The DB optimizer can't see through the proc implementation, so you get a full scan of the results.

So before you tell yourself that this will fix your results, double-check that assumption.

Note that you can always specify custom SQL for any mapping strategy with ObjectContext.ExecuteStoreQuery.

However, before you do any of this, consider that, as RPM1984 points out, your design seems to overuse inheritance. I like this quote from NHibernate in Action

[A]sk yourself whether it might be better to remodel inheritance as delegation in the object model. Complex inheritance is often best avoided for all sorts of reasons unrelated to persistence or ORM. [Your ORM] acts as a buffer between the object and relational models, but that doesn't mean you can completely ignore persistence concerns when designing your object model.



来源:https://stackoverflow.com/questions/4642443/entity-framework-table-per-type-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!